【问题标题】:Why is that sleeping inside a thread causes problems with `notify`?为什么在线程中休眠会导致“通知”出现问题?
【发布时间】:2013-12-03 06:08:36
【问题描述】:

驱动程序.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..."); 
        }
    }
}

上面的代码不会notifyThreads,因为下面这行:

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

请结合整个班级的背景来看看这句话。如果将该行放在Main Threadsynchronized 块内,我很难确定这个简单的概念验证会失败的原因。

谢谢

【问题讨论】:

  • 我认为这是一条红鲱鱼。我怀疑问题是其中一个子线程首先进入关键块(在obj 上同步),因此父线程从不 到达obj.notify 孩子的@ 987654329@(同样,如果父母先进入,信号将在孩子等待它之前出现)。
  • 对我来说,进入临界区然后休眠 20 秒没有多大意义。你永远不会在实时操作系统中这样做,因为如果低优先级任务首先进入临界区,然后决定通过睡觉来浪费每个人的时间,这会导致优先级倒置。
  • 你为什么要使用这样的static 互斥锁?您正在等待、通知和同步一个 obj。
  • 是的,我知道。我试图弄清楚当synchronizing 时,您实际上可以通过调用wait 来删除lock 标志,并允许其他synchronized 块继续处理object,然后notify 其他@987654337 @ 块 lock 标志已被禁用。
  • @user2864740 我明白你现在的意思了。这很有意义!你为什么不把它作为答案,至少我可以把它标记为正确的答案。

标签: java multithreading wait notify


【解决方案1】:

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

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

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

如果你运行它足够多次,有时两个子线程都会先获取锁并完成。

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

【讨论】:

    【解决方案2】:

    阅读doc

    唤醒一个正在等待该对象的线程 监控

    如果它正在休眠,那么它就不会等待。

    还有其他相关的问题,当其他线程处于睡眠状态时无法到达通知行,因为它保持监视器(锁定)并且其他线程无法在同步块内运行。总是这样,因为等待和通知都必须在相关的同步块内运行(针对同一个监视器)。

    【讨论】:

      【解决方案3】:

      sleep 持有锁,但wait 没有。因此,当您的主线程处于睡眠状态时, thr 和 thr2 都无法获得锁,直到主线程通知它们。那一刻,他们开始等待,收不到任何notify()

      【讨论】:

        【解决方案4】:

        问题是sleep并没有释放monitor,即:在主线程休眠的同时,其他所有线程都无法进入同步块,所以基本上都是和主线程一起休眠。

        主线程醒来的那一刻,它确实通知了,但是由于还没有人进入wait()的位置,所以没有人在听。然后主线程等待并因此释放监视器,所以现在所有线程都可以进入wait() 状态,但没有人可以唤醒它们。 -> 死锁

        【讨论】:

          猜你喜欢
          • 2015-10-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-02-23
          • 1970-01-01
          相关资源
          最近更新 更多