El hilo no vuelve después de notifyall ()

Soy nuevo en multithreading con Java. He hecho algunas investigaciones, he leído tutoriales y he realizado pruebas, pero estoy atascado con este problema. Básicamente, estoy configurando el esqueleto de un juego, y me gustaría tener la clase de actividad principal, una clase de subproceso que contiene métodos, realizar operaciones lentas (leer archivos y descomprimir contenido en búferes), y tener un hilo que Es el bucle de juego reaccionar a las operaciones de la interfaz de usuario.

En primer lugar, tengo la clase de actividad principal que instancia y inicia un subproceso separado:

public class ExperimentsActivity extends Activity { // This is just a container class with some member data such as ByteBuffers and arrays TestClass tclass = new TestClass(this); // Main looping thread MainLoopThread loop; Thread mainLoop; // Start the main looping thread which will trigger the engine's operations loop = new MainLoopThread(tclass); mainLoop = new Thread(loop); mainLoop.start(); loop.setRunning(true); (...) } 

Entonces, tengo la clase MainLoopThread que implementa el hilo para la lógica del juego:

 public class MainLoopThread implements Runnable { public boolean running; private TestClass baseData; // Thread for data loading/unpacking ( CLASS DEFINITION BELOW ) GFXUnpack dataUnpack; Thread dataUnpackThread; public MainLoopThread( TestClass testClassStructure ) { running = false; baseData = testClassStructure; } public void setRunning ( boolean run ) { if ( run == true ) { // Launch the thread which manages loading and unpacking graphics dataUnpack = new GFXUnpack(baseData.filepack[0]); dataUnpackThread = new Thread(dataUnpack); dataUnpackThread.start(); dataUnpack.setRunning(true); fileOpened = false; // Open the GFX packet file try { synchronized (this) { dataUnpack.setOperation(2); Log.d("MainLoopThread", "File opening : waiting..."); while ( dataUnpack.fileOpened == false ) { wait(); } Log.d("MainLoopThread", "File opening wait completed"); } if ( dataUnpack.outCode == -1 ) Log.d("MainLoopThread", "File opening error !!"); else fileOpened = true; Log.d("MainLoopThread", "File opening completed"); } catch ( Exception exp ) { Log.d("MainLoopThread", "File opening code exception !!" + exp); } } else if ( dataUnpack.running == true ) dataUnpack.setRunning(false); running = run; } // ------------------------------------ // Here is the main looping thread. All the events related to loading // and unpacking graphics go here public void run() { while (running) { synchronized (this) { // ------ Read a GFX packet and update texture pixels if ( fileOpened == true ) { try { // ( Do some stuff... ) wait(); } catch ( Exception exp ) { Log.d("MainLoopThread", "Exception thrown !! " + exp ); } } } // ( Thread-out code removed. Anyway, it never passed here ) } 

Y finalmente, la clase de hilo GFXUnpack , que contiene el código que abre el archivo en la tarjeta SD, lee material en él y escribe en los búferes:

 public class GFXUnpack implements Runnable { // ------------- public boolean running = false; private Filedata fdata; private int operation = 0, parameter = 0; public boolean fileOpened; public int outCode; // Used to signal the caller about the outcome of the operation // ------------------------------ public GFXUnpack ( Filedata packetDataStructure ) { this.fdata = packetDataStructure; } // -------- public void setRunning ( boolean run ) { running = run; operation = 0; fileOpened = false; outCode = 0; parameter = 0; } // -------- public void setOperation ( int op ) { operation = op; } // --- public void setOperation ( int op, int parm ) { operation = op; parameter = parm; } // --------- public synchronized void run() { while (running) { try { switch ( operation ) { case ( 2 ) : // Open the gfx data file ( ...do stuff... ) break; } // --------- try { ( ...Do some stuff here... ) Log.d("GFXUnpack", "Mapping file"); ( ...Do some stuff here... ) Log.d("GFXUnpack", "Mapped file"); fileOpened = true; outCode = 1; } catch ( Exception e ) { Log.d("GFXUnpack", "File opening exception !! " + e); outCode = -1; } finally { operation = 0; parameter = 0; notifyAll(); Log.d("GFXUnpack", "Notified file opening"); } } break; // ---------------- } // ----- Other cases here... } finally { } } } 

Cuando ejecuto lo anterior, la salida del depurador es:

MainLoopThread Abrir archivo: esperando …
Archivo de asignación de GFXUnpack
GFXUnpack Archivo asignado
GFXUnpack Apertura de archivos notificados

Luego, la aplicación se bloquea y tengo que forzar cerrarla. Pensé, ya que llamo notifyAll() en el método run() de GFXunpack (en el bloque finally{} ), que el thread llamador (MainLoopThread) procedería y vería el mensaje del depurador 'File opening completed', pero el La aplicación se bloquea en su lugar.

¿Alguien tiene alguna idea de por qué esto está sucediendo?

La instancia MainLoopThread espera en this (una instancia de MainLoopThread ), y la instancia GFXUnpack notifica sobre this (una instancia de GFXUnpack ). Por lo tanto, el notificador no notifica el hilo en espera.

Los dos objetos deben utilizar la misma instancia de objeto para esperar y notificar. Y aún mejor, debes usar abstracciones de nivel superior del paquete java.util.concurrent , como Semaphores, CountDownLatches, etc., en lugar de estos métodos de bajo nivel difíciles de usar.

Por otra parte, wait() siempre debe ser llamado en un bucle que comprueba si la condición necesaria para despertar se realiza y comienza a esperar de nuevo si no es, debido a espurios despertares.

  • Diferencia entre el hilo principal y el hilo de interfaz de usuario
  • Cómo matar un hilo en Android?
  • Cómo solucionar el problema de las llamadas de la biblioteca NDK que congela el subproceso de la interfaz de usuario
  • Java.util.concurrent.TimeoutException android.view.ThreadedRenderer.finalize () tiempo de espera transcurridos 10 segundos
  • Progressdialog lento para mostrar en Android
  • Llamar a un AsyncTask de otro AsyncTask
  • La mejor manera de enviar solicitudes HTTP GET ansynchronously en Android?
  • ¿Es posible detener un hilo cuando el usuario pulsa la tecla de retroceso?
  • Android gestión de hilos onPause
  • ¿Cómo puede el puerto AsyncTask de Android a Java?
  • Cómo ejecutar un hilo Runnable en Android?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.