我是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)会继续,我会看到调试器消息'文件打开已完成',但应用程序挂起。
有没有人知道为什么会这样?
答案 0 :(得分:3)
MainLoopThread
实例等待this
(MainLoopThread
的实例),GFXUnpack
实例通知this
({{1}的实例}})。因此,通知程序不会通知等待的线程。
这两个对象必须使用相同的对象实例来等待和通知。更好的是,您应该使用GFXUnpack
包中的更高级抽象,如信号量,CountDownLatches等,而不是这些难以使用的低级方法。
此外,应始终在一个循环中调用java.util.concurrent
,该循环检查是否已实现唤醒所需的条件,如果不是,则由于虚假的唤醒而再次开始等待。