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

java:wait()方法即使在调用notifyAll()之后仍保持等待

欧旻
2023-03-14

考虑以下代码

public class ThreadTest1
{
private static final long startTime = System.currentTimeMillis();

    public static void main(String args[])
    {
        Thread ct = new Thread(new ChildThread());
        ThreadTest1.print("starting child threads in MAIN");
        ct.start();
        synchronized(ct)
        {
            try
            {

            ThreadTest1.print("about to start wait() in MAIN");
            ct.wait();
            ThreadTest1.print("after wait() in MAIN");
            }
            catch(Exception e)
            {
            ThreadTest1.print("Exception in MAIN");
            }
        }
    }

    public static void print(String s)
    {
    System.out.println("Millisecond : "+(System.currentTimeMillis()-ThreadTest1.startTime)+"\t: "+s);
    }
}

class ChildThread implements Runnable
{
    public void run()
    {
        synchronized(this)
        {

        try
        {
        ThreadTest1.print("before thread notifyAll in CHILD");
        notifyAll();
        ThreadTest1.print("notifyAll over, sleep starts in CHILD");
        Thread.sleep(10000);
        ThreadTest1.print("after thread sleep in CHILD");

        }
        catch(Exception e)
        {
        ThreadTest1.print("Exception in CHILD");
        }
        ThreadTest1.print("End of run method in CHILD");
        }
    }
}

结果如下:

Millisecond : 12        : starting child threads in MAIN
Millisecond : 13        : about to start wait() in MAIN
Millisecond : 13        : before thread notifyAll in CHILD
Millisecond : 13        : notifyAll over, sleep starts in CHILD
Millisecond : 10015     : after thread sleep in CHILD
Millisecond : 10015     : End of run method in CHILD
Millisecond : 10016     : after wait() in MAIN

notifyAll()在13毫秒时被调用。但是,控件仅在10016毫秒时退出等待()。

从上面给出的代码中可以看出,在进行了通知()调用之后,等待()调用似乎没有立即结束。

但是,包括Java API在内的所有文档都指定,调用wait()的方法应该在notify()调用之后立即获得锁。

如果在调用通知()时等待()不会结束,那么对通知()的需求就会变得无效,因为即使没有调用通知(),调用等待()的方法也会在新线程的run方法结束时自动获得控制。

如果我在这里犯了一个错误,等待有人抛出一些光。

共有3个答案

张璞
2023-03-14

这里有两个问题:

>

  • wait和notify在相同对象上调用,并在相同对象上同步的同步块内调用。你的不一样。一个位于名为ct的thead上,另一个位于ChildThread类型的Runnable上。

    在等待之前,您正在呼叫start。很可能在主线程开始等待之前调用notify。所以你可能会错过通知。在修复点1后,尝试调整代码,以使等待和通知间隔最小化。

  • 宋昊然
    2023-03-14

    根据其他答案的建议,这里是一个可行的实现。请注意,我还将睡眠移到了synchronized块之外。通常,同步块应尽可能短。。。

    public class ThreadTest {
    
        private static final long startTime = System.currentTimeMillis();
    
        public static void main(String args[]) {
            Thread ct = new ChildThread();
            ThreadTest.print("starting child threads in MAIN");
            ct.start();
            try {
                ThreadTest.print("about to start wait() in MAIN");
                synchronized (ct) {
                    ct.wait();
                }
                ThreadTest.print("after wait() in MAIN");
            } catch (Exception e) {
                ThreadTest.print("Exception in MAIN");
            }
        }
    
        public static void print(String s) {
            System.out.println("Millisecond : " + (System.currentTimeMillis() - ThreadTest.startTime) + "\t: " + s);
        }
    
        private static final class ChildThread extends Thread {
            public void run() {
                try {
                    ThreadTest.print("before thread notifyAll in CHILD");
                    synchronized (this) {
                        notifyAll();
                    }
                    ThreadTest.print("notifyAll over, sleep starts in CHILD");
                    Thread.sleep(1000);
                    ThreadTest.print("after thread sleep in CHILD");
    
                } catch (Exception e) {
                    ThreadTest.print("Exception in CHILD");
                }
                ThreadTest.print("End of run method in CHILD");
            }
        }
    }
    
    索瀚海
    2023-03-14

    问题是您正在通知并等待不同的对象。您可以在线程上wait()并在run()方法中调用this。。。这是一个子线程

    您将ChildThread类命名错误,这一事实掩盖了这一点。这个名称意味着它是一个线程子类,但实际上它是一个可运行的子类。

     类似资料:
    • 我正在寻找一个元素http://ntry.com/#/stats/ladder/round.php,但在尝试了几种方法后,我一直未能找到它,包括通过css选择器的ind_元素,通过xpath的ind_元素。。。等等 即使我使用WebDriverWait,我还是失败了。有什么问题吗? 我使用隐式等待,但这也会产生相同的错误。不使用Wait也会导致NoTouchElementException。 网站

    • 我正在使用jsp将数据发布到servlet,但是发布数据之后,我希望保留在相同的jsp上。简单地说:1)我这里有一个带有两个文本框的jsp。我使用javascript在单击按钮时将数据从一个复制到另一个。2)我使用相同的按钮将数据发布到数据库。3)我希望两个操作一次完成,不应该转到第三个jsp(servlet发布结果),但是,应该转到我使用的另一个jsp。 我可以单独处理这两件事,但放在一起我就做

    • 问题内容: 我有很多代码, 调用时处理器很小,有时会导致性能问题(100毫秒),因此我想知道当前等待对象释放的线程是什么。 我想在调用之前打印所有等待对象释放的线程 问题答案: 是否所有线程都在资源上等待相同的条件?如果是,则可以尝试替换,尽管实际上不建议这样做。AFAIK,无法“检索”在给定对象上等待的所有线程的列表(尽管您可以通过编程方式获取进程的线程转储并查看线程,但是我敢肯定那不是您拥有的

    • 我们将设置为 1 小时,如下所示(以前设置为 72H) 使用以下Kafka命令行工具,我们将kafka 设置为< code>1H。我们的目标是清除topic - 中比1H旧的数据,因此我们使用了以下命令: 此外 两个命令都运行无误。 但问题是关于Kafka的数据,它比1H更老,仍然存在! 实际上,没有从主题分区中删除任何数据。我们有HDP Kafka集群版本1.0x和ambari 我们不明白为什么

    • 问题内容: 我是Java多线程的新手。我已经进行了一些研究,阅读了教程并进行了测试,但是我仍然遇到这个问题。基本上,我正在设置游戏的骨架,我想拥有一个主要的活动类,一个包含方法的线程类,执行各种慢速操作(读取文件并将内容解压缩到缓冲区),并具有一个线程是游戏循环对UI操作的反应。 首先,我有main活动类,该类实例化并启动一个单独的线程: 然后,我有了实现游戏逻辑线程的类: 最后,线程类(其中包含