这是某种Java拼图游戏,我偶然发现,无法真正解释。也许有人可以吗?
短时间后,以下程序挂起。有时在2个输出之后,有时在80个输出之后,但几乎总是在正确终止之前。如果第一次没有发生,您可能必须运行几次。
public class Main {
public static void main(String[] args) {
final WorkerThread[] threads = new WorkerThread[]{ new WorkerThread("Ping!"), new WorkerThread("Pong!") };
threads[0].start();
threads[1].start();
Runnable work = new Runnable() {
private int counter = 0;
public void run() {
System.out.println(counter + " : " + Thread.currentThread().getName());
threads[counter++ % 2].setWork(this);
if (counter == 100) {
System.exit(1);
}
}
};
work.run();
}
}
class WorkerThread extends Thread {
private Runnable workToDo;
public WorkerThread(String name) {
super(name);
}
@Override
public void run() {
while (true){
if (workToDo != null) {
workToDo.run();
workToDo = null;
}
}
}
public void setWork(Runnable newWork) {
this.workToDo = newWork;
}
}
现在,很明显,繁忙的等待循环通常不是一个好主意。但这不是改善,而是了解正在发生的事情。
当
WorkerThread.setWork()
为synchronized
或WorkerThread.workToDo
字段设置为volatile
时,由于一切正常,因此我怀疑存在内存问题。但是为什么会这样呢?调试无济于事,一旦您开始逐步执行,一切都会按预期进行。
一个解释将不胜感激。
最佳答案
这些行之间直接发生问题:
workToDo.run();
workToDo = null;
假设发生以下事件序列:
- Original Runnable runs. "Ping!".setWork() called
- Ping! thread realizes workToDo != null, calls run(), the stops between those two lines
- "Pong!".setWork() called
- Pong! thread realizes workToDo != null, calls run()
- "Ping!".setWork() called
- Ping! thread resumes, sets workToDo = null, ignorantly discarding the new value
- Both threads now have workToDo = null, and the counter is frozen at 2,...,80
Program hangs