调用 wait() 不会停止正确的线程

Calling wait() doesn't stop the correct thread

我是 java 中的多线程新手。我正在尝试 运行 一个可以模拟多个 "Writers" 将数据作为输出写入的程序。

我希望所有的作者都在某个时候停下来,所以我正在对他们调用 wait(),但它不起作用。我知道问题出在哪里,但我不知道为什么会发生。

public void run() {
    ExecutorService executor = Executors.newFixedThreadPool(nbOfWriters);
    try {
        // Create a list with all the writers that should run at the same time
        Writer[] writers = new Writer[nbOfWriters];
        for (int i = 0; i < nbOfWriters; i++) {
            writers[i] = new Writer(i);
            executor.execute(writers[i]);
        }
        /*
        Expected outcome:
        start every writer -> wait 3 seconds
        pause every writer -> wait 3 seconds
        run every writer -> wait 3 seconds
        end
        */
        TimeUnit.SECONDS.sleep(3);
        for (Writer writer : writers) {
            synchronized (writer) {
                System.out.println("HERE 1");
                writer.wait();
                System.out.println("HERE 2");
            }
        }

        TimeUnit.SECONDS.sleep(3);
        for (Writer writer : writers) {
            synchronized (writer) {
                writer.notify();
            }
        }
        Thread.sleep(3);
        // End of the test
        for (Writer writer : writers) writer.end();
    } 
    catch (InterruptedException ex) {
        System.out.println(ex.getMessage());
    }
    finally {
        try {
            executor.shutdown();
            executor.awaitTermination(5, TimeUnit.SECONDS);
        } 
        catch (InterruptedException ex) {
            ex.getMessage();
        }
        finally {
            executor.shutdownNow();
        }
    }
}

作家们只是把东西写成输出(这里不重要)。 我添加了打印语句 "HERE 1" 和 "HERE 2" 来显示程序失败的地方。基本上"HERE 2"是永远达不到的。

理论上应该发生的情况是我将数据写入 3 秒,然后 3 秒没有数据,然后再次将数据写入输出。

实际输出为: 东西被写为输出 3 秒。 "HERE 1" 已打印。 内容继续显示为输出,没有暂停,没有 "HERE 2" 并且程序永远不会停止。

在我看来 wait() 停止了错误的线程。

wait() 的文档说:

Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object.

所以主线程是在 "HERE 2" 之前等待的,因为它一直在等待,所以它永远无法到达 notify

我不确定是否有明确的方法来做你想做的事(告诉另一个线程等待)。有一些已弃用的 API 很好地解释了为什么你不应该使用它们:https://docs.oracle.com/javase/7/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html

Shouldn't writer.wait() call wait in the specific writer thread like other methods would?

没有

声明,writer.wait(); 使用 writer 对象作为 monitor。监视器应该以非常特定的方式使用*。它允许一个线程等待某个(可能未知的)其他线程完成一项任务。想要等待的线程通过调用 o.wait();

一个线程无法使使另一个线程调用一个函数。一个线程根本无法 另一个线程做任何事情。线程执行它们正在执行的代码告诉它们做的事情,并且在一个设计良好的程序中,该代码告诉它们彼此合作。线程 A 请求 线程 B 做某事有多种方法,但要由 编写在线程 A 中运行的代码来完成询问,由您编写在线程 B 中运行的代码,该代码可以识别何时被询问,然后执行任何操作。


* 请参阅 Oracle "guarded block" tutorial
笔记!本教程没有使用 "monitor" 这个词,但它讨论的是相同的模式。