Concurrencia en
Android
Repaso de
Crear un thread
•
Instanciar un Thread, con el método runsobreescrito
•
Intanciar un objeto que cumpla el interfazRunnable y pasárselo al constructor de
Thread !
interface Runnable { void run();
Ejecutar un Thread
•
Llamar al método startImplementando
Runnable
!
public class Biteme implements Runnable {
!
@Override
public void run() {
//Ejecuta en paralelo
} }
!
t = new Thread(new Biteme()); t.start();
b = new Thread(new Biteme()); b.start();
Heredando de Thread
!
public class Biteme extends Thread {
!
@Override
public void run() {
//Ejecuta en paralelo } } ! t = new Biteme(); t.start(); b = new Biteme(); b.start(); Y se crean
Heredando de Thread
clase interna
!
public class Cup { public int level;
private class Biteme extends Thread {
@Override
public void run() {
//Ejecuta en paralelo, tiene acceso a Cup
level = 3;
}
public void fill() {
Biteme b = new Biteme();
b.start();
} }
Heredando de Thread
clase interna anónima
public class Cup { public int level;
public void fill() {
Thread b = new Thread(){
@Override
public void run() {
level = 3; } }; b.start(); } }
Thread
•
Thread, metodos de clase interesantes:•
currentThread(): referencia al thread actual•
activeCount(): numero de threads activos•
dumpStack(): pila en stderr•
sleep(int ms)Executor
java.util.concurrent
•
Interfaz para ejecutar objetos de tipoRunnable
•
Puede hacerlo en serie, en paralelo, conunos cuantos threads, etc.
!
interface Executor {
public void execute(Runnable r); };
Executor:
ejemplo de uso
!
SerialExecutor s = new SerialExecutor();
BiteMe b = new BiteMe(); //Runnable
s.execute(b);
ExecutorService
•
Es un interfaz que hereda de Executor•
Con extras para controlar el progresoFuture<?> submit(Runnable task)
•
Future tiene un método get() que devuelvenull si ha acabado y otra cosa si no
•
Future tiene más métodos para controlarExecutorService
!
ExecutorService es = Executors.newFixedThreadPool(3); BiteMe b = new BiteMe(); //Runnable
BiteMe bx = new BiteMe(); //Runnable
Future<?> fut1 = es.submit(b); Future<?> fut2 = es.submit(bx);
!
try{
if(fut1.get() == null){
System.out.println("b ha acabado bien"); }
if(fut2.get() == null){
System.out.println("bx ha acabado bien"); }
}catch(ExecutionException e){
//ha fallado la ejecucion
}catch(InterruptedException e){
//se ha interrumpido
}finally{
es.shutdown(); //acabo con el executor service
Interrupciones
•
Son mala idea como método decomunicación
•
Mejor comunicarse con variables y que elthread salga o haga lo que sea el mismo
•
Pueden ser necesarios si tengo un threaden sleep
Condiciones de carrera
•
Si tengo varios hilos, puedo tenercondiciones de carrera
•
Ojo con tocar datos compartidos sinSincronización
•
Puedo esperar que un thread acabellamando a su método join() puedo poner
timeout
!
t.start();
Sincronización
•
Puedo esperar que todos los threads de unexecutor service acaben, tiene timeout:
awaitTermination()
•
Antes tengo que haber llamado ashutdown(), “ya no admitas más threads, ve saliendo”
!
Sincronización:
synchronized
•
Hay un cierre reentrante asociado a losobjetos (un objeto es un monitor)
•
Se coge (se entra al monitor) llamando a unmétodo synchronized o rodeando un bloque
Sincronización:
synchronized
public class Cup {
public synchronized void fill() {
//Estoy en el monitor de esta instancia de Cup
}
public void fill2() {
BiteMe b = new BiteMe();
synchronized(b){
//Estoy en el monitor b
} }
Sincronización:
synchronized
public class Cup {
public synchronized void fill() {
//Estoy en el monitor de esta instancia de Cup
}
public void fill2() {
synchronized(this){
//Estoy en el monitor de esta instancia de Cup
} }
Sincronización:
synchronized
public class Cup {
public static synchronized void fill3() {
//Estoy en el monitor de la clase Cup
} }
•
Ojo, los métodos estáticos cogen el
cierre de la clase
Sincronización:
synchronized
public class Cup {
public synchronized void fill() {
//Estoy en el monitor de esta instancia de Cup
}
public synchronized void fill2() {
fill(); //No hay deadlock, es un monitor
} }
Sincronización:
comunicación
•
BlockingQueue: FIFOs bloqueantes, comocanales
•
ConcurrentMap: DiccionarioSincronización
•
Decorador sincronizado para colecciones (hayotros especializados):
public static <T> Collection<T> synchronizedCollection(Collection<T> c)
•
Ojo, hay que sincronizar el acceso!
Collection c = Collections.synchronizedCollection(myCollection); ...
synchronized(c) {
Iterator i = c.iterator(); // Ojo, dentro de un bloque synchronized
while (i.hasNext()) foo(i.next()); }
Concurrencia en
Android
Problemas
•
GUI no responde: las callbacks no puedenestar mucho rato bloqueadas; usar threads
•
Threads en background no puedenAlternativas
•
Crear threads, esperar a que acaben,actualizar la GUI, join() o awaitTermination()
•
Usar View.post para actualizar la GUI•
Usar AsyncTask, divide tareas entre threadsen background y threads de GUI
•
No actualizo la GUI si no estoy en el hiloView.post
•
Tengo un hilo que he creado corriendo enbackground
•
Quiero que cambie la UI•
Por ejemplo una barra de progreso•
Uso el método post para pasarle unRunnable que ejecutará el hilo asociado al
Ejemplo:
Botón para un tono:
public class Tono implements OnClickListener { View but; void playSound(){ //suena } Tono(View v) { but = v; //inicializo el tono }
private class Pressme implements Runnable {
boolean p; View v;
Pressme(View b, boolean pressed){
p = pressed;
v = b; }
@Override
public void run() {
v.setEnabled(!p); }
Ejemplo:
Botón para un tono:
!
@Override
public void onClick(View arg0) {
arg0.setEnabled(false);
Thread t = new Thread(){
public void run(){
playSound();
try{
Thread.sleep(3*1000);
}catch(InterruptedException e){}
but.post(new Pressme(but, false));
}
};
t.start(); }
Ejemplo: OJO
•
El hilo tiene una referencia al botón•
Que vive en la Activity•
¿Qué sucede si la Activity se recrea?•
Por ejemplo, si giran la pantalla…AsyncTask
•
Crea un hilo cuando se llama al métodoexecute()
•
Ejecuta algunos métodos en el contexto deese hilo
•
Y otros en el contexto de la GUI (sonAsyncTask
private class SomeTask extends AsyncTask<Type1, Type2, Type3> { public Type3 doInBackground(Type1... params) {
return(doNonUiStuffWith(params)); }
public void onPostExecute(Type2 result) {
doUiStuff(result); }
} …
new SomeTask().execute(type1VarA, type1VarB);
AsyncTask
•
Los tres parámetros del tipo genérico:AsyncTask<Type1, Type2, Type3>
•
Type1 Parámetros dedoInBackground(Type1...)
•
Type 2 registro de progresoonProgressUpdate(Type2...)