为什么在线程内部睡眠会导致`notify`出现问题?

时间:2013-12-03 06:08:36

标签: java multithreading wait notify

Driver.java

public class Driver {

    static Object obj = new Object();

    public static void main(String [] args) throws InterruptedException
    {
        Thread thr = new Thread(new Runnable(){

            @Override
            public void run() {
                System.out.println("Thread 1: Waiting for available slot.");
                synchronized(obj){

                    try {
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println("Thread 1: Found slot!");

                    long x = 0;
                    while(x < Integer.MAX_VALUE) x++;

                    System.out.println("Thread 1: Completed processing.");
                    System.out.println("Thread 1: Notifying other waiting threads.");

                    obj.notify();
                }
            }

        });

        Thread thr2 = new Thread(new Runnable(){

            @Override
            public void run() {
                System.out.println("Thread 2: Waiting for available slot.");
                synchronized(obj){
                    try {
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println("Thread 2: Found slot!");

                    long x = 0;
                    while(x < Integer.MAX_VALUE) x++;

                    System.out.println("Thread 2: Completed processing.");
                    System.out.println("Thread 2: Notifying other waiting threads.");

                    obj.notify();
                }
            }

        });

        thr.start();
        thr2.start();

        System.out.println("Main Thread: All processing units busy.");
        // Thread.sleep(2000); // Enable this and disable the other Thread.sleep(...) and NOW we are good. But again, 'why?' is the question.

        synchronized(obj){
            Thread.sleep(2000); // This causes a failure. Move it outside the synchronized and it will work why?
            System.out.println("Main Thread: Found ONLY 1 available slot.");
            obj.notify();

            obj.wait(); // JVM should catch this as the last request so it has the least priority.
            System.out.println("Main Thread: Finished and exiting..."); 
        }
    }
}

由于以下行,上述代码不会notify Threads

Thread.sleep(2000); // This causes a failure. Move it outside the synchronized and it will work why?

请在整个班级的背景下看一下这一行。如果该行被放置在synchronized的{​​{1}}块中,我很难确定这个简单的概念验证失败的原因。

谢谢

4 个答案:

答案 0 :(得分:1)

阅读doc

  

唤醒正在等待此对象的单个线程   监测

如果它正在睡觉,那么它就没有等待。

还有其他相关问题,当另一个线程处于休眠状态时,无法访问通知线,因为它保持监视器(锁定)而另一个线程无法在同步块内运行。这总是那样,因为wait和notify必须在相关的syncrhonized块内运行(针对同一个监视器)。

答案 1 :(得分:1)

sleep持有锁,但wait没有。所以当你的主线程处于休眠状态时,thr和thr2都无法获得锁定,直到主线程通知它们为止。在那一刻,他们开始等待,无法接收任何notify()

答案 2 :(得分:1)

问题不是睡眠,而是主线程几乎总是在创建的线程的一个(有时是两个)之前获取锁。如果您只是在同步块内打印,那么发生的事情会更清楚:

synchronized(obj) {
    System.out.println("this thread acquired the lock");

你会看到输出几乎总是线程#1,然后是主线程,最后是线程#1完成后线程#2(但是main已经返回)。

如果你运行足够多次,有时两个子线程首先获得锁定并完成。

将睡眠移动到主线程中同步块之外的原因是它允许两个子线程到达它们各自的等待语句。

答案 3 :(得分:1)

问题是睡眠不会释放监视器,即:当主线程处于休眠状态时,所有其他线程都无法进入同步块,因此它们基本上与主线程一起休眠。

当主线程被唤醒时,它确实会通知,但由于还没有人进入wait()位置,所以没有人在听。然后主线程等待并因此释放监视器,所以现在所有线程都可以进入wait()状态,但没有人可以将它们唤醒。 - &GT;死锁