java - example - threadpool android
java.lang.IllegalMonitorStateException: objeto no bloqueado por thread antes de wait()? (3)
Estoy usando el cuadro de diálogo de progreso. Necesito detener el hilo cuando el usuario cierra el cuadro de diálogo de progreso. Desafortunadamente, la excepción me ayuda por favor.
En la clase interna
class UpdateThread extends Thread{
public void run() {
while (true){
count=adapter.getCount();
try {
mHandler.post( new Runnable() {
public void run() {
Log.i(TAG,count+"count");
progressDialog.setMessage(count + "Device found");
}
});
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Oncreate
updateThread=new UpdateThread();
progressDialog= new ProgressDialog(GroupListActivity.this);
synchronized (this) {
updateThread.start();
}
ondismissal
progressDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
try {
synchronized (this) {
updateThread.wait(300);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i(TAG,"Thread is stopped");
}
});
Esto está mal:
synchronized(foo) {
foo.wait();
}
El problema es, ¿qué va a despertar este hilo? Es decir, ¿cómo se garantiza que el otro subproceso no invocará a foo.notify()
antes de que el primer subproceso llame a foo.wait()
? Eso es importante porque el objeto foo no recordará que fue notificado si la llamada de notificación ocurre primero. Si solo hay una notificación (), y si ocurre antes de la espera (), la espera () nunca volverá.
Así es como se espera que se usen wait and notify:
private Queue<Product> q = ...;
private Object lock = new Object();
void produceSomething(...) {
Product p = reallyProduceSomething();
synchronized(lock) {
q.add(p);
lock.notify();
}
}
void consumeSomething(...) {
Product p = null;
synchronized(lock) {
while (q.peek() == null) {
lock.wait();
}
p = q.remove();
}
reallyConsume(p);
}
Las cosas más importantes a tener en cuenta en este ejemplo son que hay una prueba explícita para la condición (es decir, q.peek ()! = Null), y que nadie cambia la condición sin bloquear el bloqueo.
Si se llama primero al consumidor, encontrará la cola vacía y esperará. No hay un momento en el que el productor pueda deslizarse, agregar un Producto a la cola y luego notificar el bloqueo hasta que el consumidor esté listo para recibir esa notificación.
Por otro lado, si se llama primero al productor, entonces se garantiza que el consumidor no llame a wait ().
El ciclo en el consumidor es importante por dos razones: una es que, si hay más de un hilo de consumidor, entonces es posible que un consumidor reciba una notificación, pero luego otro consumidor se cuela y roba el Producto de la cola. Lo único razonable para el primer consumidor en ese caso es esperar nuevamente para el próximo Producto. La otra razón por la que el ciclo es importante es porque el Javadoc dice que Object.wait () puede regresar aunque el objeto no haya sido notificado. Eso se llama "activación espuria", y la forma correcta de manejarlo es retroceder y esperar nuevamente.
También tenga en cuenta: el bloqueo es private
y la cola es private
. Eso garantiza que ninguna otra unidad de compilación va a interferir con la sincronización en esta unidad de compilación.
Y tenga en cuenta: el bloqueo es un objeto diferente de la cola en sí. Eso garantiza que la sincronización en esta unidad de compilación no interferirá con la sincronización que realice la implementación de Queue (si existe).
NOTA: Mi ejemplo reinventa una rueda para demostrar un punto. En el código real, usaría los métodos put () y take () de un ArrayBlockingQueue que se encargaría de todas las esperas y notificaciones por usted.
Parece que estás intentando synchronized
y wait
donde no deberías estar.
Si realmente quieres esperar a que termine el hilo, deberías estar haciendo algo como esto
En su UpdateThread
:
class UpdateThread extends Thread{
public AtomicBoolean stopped = new AtomicBoolean(false);
public void run() {
while (!stopped.get()){
.....
En tu creación:
updateThread = new UpdateThread();
progressDialog = new ProgressDialog(GroupListActivity.this);
updateThread.start(); // no synchronization necessary
En tu despedida:
progressDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
try {
updateThread.stopped.set(true);
updateThread.join(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i(TAG,"Thread is stopped");
}
});
Tenga en cuenta que agregué una condición de salida a su hilo para que se detenga (como es, su hilo continuará). Probablemente desee hacer que la condición de salida sea privada y agregar un colocador para la limpieza. Además, estoy usando join
para esperar a que se complete el hilo.
Solo puede esperar en un objeto si ya tiene el bloqueo, puede intentar:
synchronized (updateThread) {
updateThread.wait(300);
}
... pero no estoy seguro de lo que estás tratando de lograr con los bloqueos.