Java等待/通知-不唤醒线程

问题描述 投票:1回答:2

我正在尝试做一些小练习以习惯于等待/通知。我正在尝试做的只是简单地启动一个线程,然后等待它使其进入睡眠状态,并通过notify唤醒它多次。

我的代码是:

public class Simple{
    static final Thread mainThread = Thread.currentThread();

    public static void main(String[] args) throws InterruptedException {
        PrintThread printer = new PrintThread(0);
        printer.start();

        synchronized (mainThread){
            System.out.println("main sleeping while waiting for printer to be started");
            mainThread.wait();
            System.out.println("main woke up");


            for (int i = 0; i < 1000; i++) {
                synchronized (printer){
                    System.out.println("added num "+i);
                    printer.numToPrint = i;
                    System.out.println("main waking up printer");
                    printer.notifyAll();
                    System.out.println("main sleeping");
                    mainThread.wait();
                    System.out.println("main woke up");
                }
            }

        }

    }
}

class PrintThread extends Thread{
    public int numToPrint = -1;

    public PrintThread(int numToPrint){
        this.numToPrint = numToPrint;
    }

    @Override
    public synchronized void run() {
        System.out.println("printer started");
        while (true){
            try {
                synchronized (Simple.mainThread){
                    System.out.println("printer waking up main");
                    Simple.mainThread.notifyAll();
                }
                System.out.println("printer sleeping");
                wait();
                System.out.println("printer woke up");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("printing num "+numToPrint);
        }
    }

}

我希望这会像

main sleeping while waiting for printer to be started
printer started
printer waking up main
printer sleeping
main woke up
added num 0
main waking up printer
main sleeping
printer woke up
printing num 0
printer waking up main
printer sleeping
main woke up
added num 1
...

相反,这样做:

main sleeping while waiting for printer to be started
printer started
printer waking up main
printer sleeping
main woke up
added num 0
main waking up printer
main sleeping

所以...似乎notify不会唤醒打印机线程?

这不应该是死锁,因为通过等待我会释放我拥有的所有锁,因此main不应在printer上有任何锁,并且printer应该能够唤醒并打印。

我在做什么错?

java multithreading wait notify
2个回答
1
投票

最有可能在Print再次调用wait()之前调用notifyAll()调用。问题在于您是否完全按照您希望的顺序来执行wait和notifyAll调用。这是两个不同的执行线程,因此当然不能保证,因此您正在获得所得到的。

实现此目的的一种更好的方法是创建一个公共的第3个共享对象,两个线程都可以获取锁定。这将使两个线程在等待访问该对象时进行同步。

[此外,您应该阅读Thread.wait的Javadocs,并通知和notifyAll。如果/当您这样做时,您将看到永远不要在Threads上调用这些方法,因为它们在执行thread.join中使用(不仅如此,我的“成名声”还是我几年前提出的错误请求)当它不在JavaDoc中导致将其添加到Javadoc中时对此进行记录。本来可以是其他人,但是在我要它之后就发生了:))


0
投票

Property:调用wait()释放锁定(它正在监视该锁定)并进入等待状态。它在同一对象上等待notify()或notifyAll()。一旦notify()或notifyAll()并在CPU中进行了调度,它会在恢复之前再次获取该锁。

当您首先在main方法中执行“ synchronized(mainThread)”时,它基本上锁定了“ mainThread”类对象。当调用mainThread.wait()时,mainThread进入等待状态(等待某人调用mainThread类对象上的notify或notifyAll)。

这次,PrintThread可能会占用CPU。这是“ synchronized(Simple.mainThread)”被安排并锁定“ Simple.mainThread”并通知所有等待“ Simple.mainThread”的线程时的时间。在此块完成之后,PrintThread释放了“ Simple.mainThread”锁。

此时主线程将在尝试从何处恢复之前尝试再次获取“ mainThread”上的锁。由于此时尚未获取“ mainThread”锁,因此主线程将获得该锁并打印“ main wake up”。

现在,在这里遇到for循环。记住:此处已获得对“ mainThread”类对象的锁定。

现在在for循环中,它获得了对“打印机”对象的锁定。执行一些计算并调用“ printer.notifyAll()”,将通知所有在“ printer”对象上等待的线程。

**这里要记住的要点是:由于代码光标仍位于“同步(打印机)”内部,因此尚未释放对“打印机”对象的锁定。 **

向前移动,打印“ main sleep”,然后调用“ mainThread.wait()”。这试图获取已获取的“ mainThread”上的锁(在块中的“ Remember:”中已提及),并且由于以后没有线程在“ mainThread”上进行通知而被卡住,并且“ synchronized(printer)”块永远不会结束,即锁定即使调用NotifyAll(),也永远不会释放“打印机”对象。

尝试从头开始在主要方法中添加以下代码,以测试上述情况。

synchronized (mainThread) {
            synchronized (printer){
                System.out.println("Before");
                mainThread.wait();
                System.out.println("After");
            }

SOLUTION:在“ printer.notifyAll()”之后关闭“ synchronized(printer)”块,以便在通知之后并在获取“ mainThread”之前释放“ printer”锁。

© www.soinside.com 2019 - 2024. All rights reserved.