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:
- Enviar tareas a un grupo de subprocesos proporciona RejectedExecutionException
- Lo que se mata con el hilo de la interfaz de usuario de Android
- ¿Aplicación de hilo único utilizar multi núcleo en android?
- Android Thread.sleep () en AsyncTask congelar la interfaz de usuario
- Cómo llamar a otra actividad después de cierto límite de tiempo
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 aplicación puede estar haciendo demasiado trabajo en su hilo principal
- ¿Cómo ejecutar la solicitud web en su propio hilo?
- Dormir un hilo hasta que un evento sea asistido en otro hilo
- Espere a que el hilo en línea termine antes de pasar al siguiente método
- RxJava No puede crear el controlador dentro de hilo que no ha llamado Looper.prepare ()
- Android ht stime, utime?
- Espere a que los hilos se completen antes de continuar
- Obtener las sugerencias de AutoCompleteTextView del servicio en un hilo independiente
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.
- Servicio de fondo de stop android después del bloqueo de actividad
- OnClick on LinearLayout with childs (tener android: duplicateParentState = "true") no activa la función