繁体   English   中英

Java多线程:所有线程准备就绪后如何通知()一个线程

[英]Java multithreading: how to notify() a single thread after all threads are ready

我正在编写一个可以让Player位于本地或远程的游戏,因此我必须阅读他使用多线程进行的“移动”。

我有一个PlayerLoop线程,该线程最初在多个Player线程上调用start() 在那之后, PlayerLoop应该以循环的方式反复唤醒单个Player (从第一个到最后一个),直到游戏结束。

但是,并非总是Player会醒来:有时PlayerLoop会通知正确的Player ,但这做得太早了( Player尚未“等待轮到他”)。

具体来说,当我第一次启动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为时过早。 如何确保仅在所有Player都在其各自的监视器上wait()后才notify() Player

除非轮到他们,否则玩家不应等待其轮到。 等待一个条件是无条件的 因此,如果您不需要等待条件,请不要等待它。 调用wait方法的原因是同步的,以便您可以完全确保需要等待。

如果有什么要等待的,等待总是很安全的。 如果没有什么可等待的,则没有理由等待。 不要等待已经发生的事情,它不会发生。

请尝试使用Java Standard API中的Semaphore ,它非常简单,而且不会造成混乱。

Object.wait和Object.notify级别太低,无法正确使用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM