notifyall()后线程没有返回

时间:2012-11-17 17:33:10

标签: java android multithreading

我是Java的多线程新手。我做过一些研究,阅读教程和完成测试,但我坚持这个问题。基本上,我正在设置游戏的骨架,我想要主活动类,包含方法的线程类,执行慢速操作(读取文件并将内容解压缩到缓冲区),并且有一个线程是游戏循环对UI操作的反应。

首先,我有一个主要的活动类,它实例化并启动一个单独的线程:

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

(...)
}

然后,我有MainLoopThread类来实现游戏逻辑的线程:

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

最后,GFXUnpack线程类,其中包含在SD卡上打开文件的代码, 读取其中的内容并写入缓冲区:

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

当我运行上面的命令时,调试器输出为:

  

MainLoopThread文件打开:等待...
    GFXUnpack映射文件
     GFXUnpack映射文件
     GFXUnpack通知文件打开

然后,应用程序挂起,我必须强制关闭它。我想,因为我在notifyAll()的{​​{1}}方法中调用run()(在GFXunpack块中),调用者线程(MainLoopThread)会继续,我会看到调试器消息'文件打开已完成',但应用程序挂起。

有没有人知道为什么会这样?

1 个答案:

答案 0 :(得分:3)

MainLoopThread实例等待thisMainLoopThread的实例),GFXUnpack实例通知this({{1}的实例}})。因此,通知程序不会通知等待的线程。

这两个对象必须使用相同的对象实例来等待和通知。更好的是,您应该使用GFXUnpack包中的更高级抽象,如信号量,CountDownLatches等,而不是这些难以使用的低级方法。

此外,应始终在一个循环中调用java.util.concurrent,该循环检查是否已实现唤醒所需的条件,如果不是,则由于虚假的唤醒而再次开始等待。