The topic does not return after notifyall ()

I am new to multithreading with Java. I did some research, read the tutorials and did the tests, but I'm stuck with this problem. Basically, I create a game’s skeleton, and I would like to have a main activity class, a stream class that contains methods, performs slow operations (reading files and unpacking contents into buffers) and has a stream, which is a game loop that responds to user interface operations .

Firstly, I have a main activity class that creates and starts a separate thread:

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 operations loop = new MainLoopThread(tclass); mainLoop = new Thread(loop); mainLoop.start(); loop.setRunning(true); (...) } 

Then I have a MainLoopThread class that implements a thread for game logic:

 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 ) } 

And finally, the GFXUnpack thread GFXUnpack , which contains the code that opens the file on the SD card, reads the material in it and writes it to buffers:

 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 { } } } 

When I run the above, the debugger output is:

MainLoopThread Opening the file: waiting ...
GFXUnpack Mapping File
GFXUnpack Mapped File
GFXUnpack File Open Notification

Then the application freezes and I need to force close it. I thought, as I call notifyAll() in the run() GFXUnpack (in the finally{} block), that the caller's thread (MainLoopThread) will continue, and I will see the debugger message “Opening file completed”, but the application hangs instead.

Does anyone have any idea why this is happening?

+4
source share
1 answer

The MainLoopThread instance expects this (the MainLoopThread instance), and the GFXUnpack instance notifies this (the GFXUnpack instance). Therefore, the notifier does not notify of the pending stream.

Two objects must use the same instance of the object to wait and notify. And even better, you should use higher-level abstractions from the java.util.concurrent package, such as Semaphores, CountDownLatches, etc., and not these low-level methods that are difficult to use.

In addition, wait() should always be called in a loop that checks to see if the condition necessary for awakening is fulfilled, and again comes to life, if it is not, due to false awakenings.

+3
source

Source: https://habr.com/ru/post/1446673/


All Articles