当前位置: 首页 > 知识库问答 >
问题:

Wait/Notify的奇怪Java行为

子车凯泽
2023-03-14

我发现了Java并发的奇怪行为。请参阅下面的下一段代码:


    public class Test {
        static CountDownLatch latch = new CountDownLatch(1);
        public static void main(String[] args) throws UnsupportedEncodingException, InterruptedException {
            final Thread t = new MyThread();
            t.start();
            synchronized (t) {
                latch.countDown();
                System.out.println("got to sleep");
                t.wait();
                System.out.println("wake up");
            }
        }

        static class MyThread extends Thread {
            @Override
            public void run() {
                try {
                    latch.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (this) {
                    System.out.println("inside run");
    //                notifyAll();
                }
            }
        }
    }

在我看来,这段代码应该挂起并永远等待,但是在控制台中的next out没有任何问题地完成了代码:

got to sleep
inside run
wake up

我试图找到一些关于如果线程死了通知锁的信息,但缺乏。我也没有在Java规范中找到任何信息。

但是如果我试图锁定其他对象(而不是thread对象),就会像我预期的那样工作得很好。

共有2个答案

薛英卫
2023-03-14

正如Jon Skeet所写的那样,在线程对象上同步是个坏主意,使用另一个:

public class Test {
    static CountDownLatch latch = new CountDownLatch(1);
    static final Object sync = new Object();

    public static void main(String[] args) throws UnsupportedEncodingException, InterruptedException {
        final Thread t = new MyThread();
        t.start();
        synchronized (sync) {
            latch.countDown();
            System.out.println("got to sleep");
            sync.wait();
            System.out.println("wake up");
        }
    }
}

static class MyThread extends Thread {
    @Override
    public void run() {
        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (sync) {
            System.out.println("inside run");
            //sync.notifyAll();
        }
    }
}

现在,在取消对sync.notifyAll()的注释之前,这段代码将永远不会结束;

宁良平
2023-03-14

这是因为您正在等待thread实例。thread在内部使用wait/notify/notifyall,所以您自己也不应该这样做--您会混淆thread,而thread也会混淆您。特别是,当线程退出时,它调用this.notifyAll()

thread.join的文档中可以看到:

此实现使用This.wait调用的循环,该循环以This.isalive为条件。当线程终止时,将调用this.notifyall方法。建议应用程序不要在thread实例上使用waitnotifynotifyall

通常情况下,尝试锁定并等待其他任何东西都无法与之交互的对象。这样,您就可以对对象上存在的与并发相关的操作进行推理,因为它们是非常有限的。只要任意代码能够在对象上同步(并调用wait/notify等),就很难证明您的代码是正确的。这就是为什么你会经常看到这样的东西:

public class Foo {
    private final Object lock = new Object();

    ... code which uses synchronized(lock) ...
}
 类似资料:
  • 问题内容: 如上面的示例,如果先进入块,则ThreadB中的后续块将告诉主线程继续。 但是我们不能保证将在)之前执行,如果ThreadB首先进入该块怎么办?会在之前执行,所以会永远挂在那里(因为不再告诉它继续执行)?通常有什么合适的方法来解决这个问题? 问题答案: 您几乎应该总是将谓词与等待/通知一起使用。也就是说,您需要可以检查的条件,例如变量变为true,队列变为空/满等。仅盲目地等待某人调用

  • 所以我更新了代码,添加了行所做的是将主线程置于Hibernate状态一段时间,因此jvm可以获得一些时间来创建一个新线程。我正在得到我的预期输出

  • 问题内容: 我正在尝试检查java中的wait / notify如何工作。 码: 输出返回 我期望在执行notify()时,等待将结束并被打印。但似乎只有完成打印后才能打印。 问题答案: 对象监视器锁需要执行相同锁的单个引用。 在你的榜样,你是对的一个实例,但使用从。相反,您应该使用单个通用锁定对象…例如 输出… 并可能根据线程调度更改位置。 您可以尝试将睡眠排除在障碍之外。这将释放监视器锁定,从

  • 如果有人理解java编译器为什么这么做,请解释一下。

  • 下面的代码是一个小示例,可以轻松重现问题。所以我有 String 类型的变量,它设置了默认值。我有3种方法: getter 塞特 将字符串转换为布尔值的方便方法 自省不会将getter作为readMethod返回,将setter作为WriteMethod返回。相反,它将isTest()方法作为readMethod返回。setter为空。 从文档中我了解到,如果类型是boolean,那么" is "

  • 我在做Maven项目。我用log4j做了一个日志。但它在给定的文件中显示了一些starnge日志。我试图理解,为什么会出现这种奇怪的日志,但我不明白。请帮助我,为什么这些不需要的行会进入日志文件。 请帮我把这个拿开。 log.properties 我通过阅读这个链接创建了这个文件。 代码是 日志txt-(log.txt的一些起始行)