我正在编写一个Player
可以是本地或远程的游戏,所以我必须阅读"移动"他用多线程制作的。
我有一个PlayerLoop
线程,最初在几个start()
个线程上调用Player
。在此之后,PlayerLoop
应该以循环方式重复唤醒单个Player
(从第一个到最后一个),直到游戏结束。
但是,Player
并不总是会被唤醒:有时候PlayerLoop
会通知正确的Player
,但过早发生这种情况(Player
并非如此然而"轮到他了#34;)。
具体来说,当我第一次启动PlayerLoop
时似乎工作正常,但如果在游戏过程中我取消了比赛并开始一个新比赛,那么每个Player
只需等待轮到他们永远。
这里是PlayerLoop
:
public class PlayerLoop extends Thread {
@Override
public void run() {
System.out.println("Thread [" + Thread.currentThread().getName()
+ "] is alive.");
this.startPlayers(); // cycles Players and calls .start()
while (true) {
Player current = this.getCurrentPlayer();
current.connect(); // connect to this Player
synchronized (current) {
try {
System.out.println("Notifying Thread [" + current.getName()
+ "] that it's his turn.");
current.notify(); // the player thread "resumes" to eventually produce a "move"
current.wait(); // wait for the "move" to be ready
} catch (InterruptedException e) {
// The game loop is interrupted, terminate thread
break;
}
}
this.applyMove(current.getMove()); // use the "move"
current.disconnect(); // disconnect this Player
this.goToNextPlayer();
}
System.out.println("Terminating players...");
this.stopPlayers(); // cycles Players and calls .interrupt()
System.out.println("Thread [" + Thread.currentThread().getName()
+ "] is dead.");
}
目前我没有测试"遥控器"部分所以这里只是LocalPlayer
类,它扩展了Player
,扩展了Thread
:
public class LocalPlayer extends Player {
@Override
public void run() {
System.out.println("Thread [" + Thread.currentThread().getName()
+ "] is alive.");
while (true) {
// Wait my turn
synchronized (this) {
try {
System.out.println("Thread ["
+ Thread.currentThread().getName()
+ "] is waiting its turn.");
this.wait();
} catch (InterruptedException e) {
// We are stopping all the players, so terminate thread
break;
}
System.out.println("Thread ["
+ Thread.currentThread().getName()
+ "] has come to its turn.");
}
// Wait for mainLoop to produce a Move
synchronized (__SomeGameLoop__) {
System.out.println("Thread ["
+ Thread.currentThread().getName()
+ "] is waiting a move.");
try {
__SomeGameLoop__.wait();
} catch (InterruptedException e) {
// PlayerLoop was interrupted, and he is now interrupting me, so terminate thread
break;
}
System.out.println("Thread ["
+ Thread.currentThread().getName()
+ "] has been notified of a move.");
}
// Get produced move
this.move = __SomeGameLoop__.getMove();
// Signal monitor
synchronized (this) {
// Notify that I have read the move and that I can communicate it
this.notify();
}
}
System.out.println("Thread [" + Thread.currentThread().getName()
+ "] is dead.");
}
}
上面的代码可能不准确且过于简单,但这里是游戏输出的摘录:
Creating threads...
Thread [PlayerLoop] is alive.
Thread [Player 1] is alive.
Thread [Player 2] is alive.
Thread [Player 2] is waiting its turn.
Thread [Player 1] is waiting its turn.
Notifying Thread [Player 1] that it's his turn.
Thread [Player 1] has come to its turn.
Thread [Player 1] is waiting a move.
GameLoop notifies that a move has been done.
Thread [Player 1] has been notified of a move.
Notify that I have read that move and I can communicate it
Thread [Player 1] is waiting its turn.
Notifying Thread [Player 2] that it's his turn.
Thread [Player 2] has come to its turn.
Thread [Player 2] is waiting a move.
GameLoop notifies that a move has been done.
Thread [Player 2] has been notified of a move.
Notify that I have read that move and I can communicate it
Thread [Player 2] is waiting its turn.
Notifying Thread [Player 1] that it's his turn.
Thread [Player 1] has come to its turn.
Thread [Player 1] is waiting a move.
GameLoop notifies that a move has been done.
Thread [Player 1] has been notified of a move.
Notify that I have read that move and I can communicate it
Thread [Player 1] is waiting its turn.
Notifying Thread [Player 2] that it's his turn.
Thread [Player 2] has come to its turn.
Thread [Player 2] is waiting a move.
Terminating players...
Thread [PlayerLoop] is dead.
PlayerLoop was interrupted, and he is now interrupting me, so terminate thread [Player 2]
We are stopping all the players, so terminate thread [Player 1]
Thread [Player 1] is dead.
Thread [Player 2] is dead.
Creating threads...
Thread [PlayerLoop] is alive.
Thread [Player 1] is alive.
Notifying Thread [Player 1] that it's his turn.
Thread [Player 1] is waiting its turn.
Thread [Player 2] is alive.
Thread [Player 2] is waiting its turn.
....(and here it hangs indefinitely)....
第二次创建线程时,PlayerLoop
过早地通知Player
。如果所有notify()
Player
Player
在各自的监视器上,我怎样才能确保wait()
{{1}}?
答案 0 :(得分:3)
除非轮到他们,否则球员不应该轮到他们。等待 条件无条件。因此,如果您不需要等待条件,请不要等待它。调用wait
的方法同步的原因是您可以确保在等待之前需要等待。
如果有什么要等待,等待总是安全的。如果没有什么可以等待,没有理由等待。不要等待已经发生的事情,也不会发生。
答案 1 :(得分:1)
请从Java Standard API尝试Semaphore,这很简单,也不那么容易混淆。
Object.wait和Object.notify的级别太低而无法正确使用。