4

我是 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 File opening : waiting...
GFXUnpack 映射文件
GFXUnpack 映射文件
GFXUnpack 通知文件打开

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

有谁知道为什么会这样?

4

1 回答 1

3

MainLoopThread实例等待this(的实例)MainLoopThreadGFXUnpack实例通知this(的实例GFXUnpack)。所以通知器不会通知等待线程。

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

此外,wait()应始终在循环中调用,以检查唤醒所需的条件是否已实现,如果未实现,则由于虚假唤醒再次开始等待。

于 2012-11-17T17:45:03.307 回答