Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
java:wait()方法即使在调用notifyAll()之后仍保持等待_Java_Multithreading_Wait_Notify - Fatal编程技术网

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

java:wait()方法即使在调用notifyAll()之后仍保持等待,java,multithreading,wait,notify,Java,Multithreading,Wait,Notify,考虑以下代码 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

考虑以下代码

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毫秒时退出等待()

从上面给出的代码来看,似乎在notify()调用之后wait()调用没有立即结束

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

如果调用notify()时wait()将无法结束,那么对notify()的需求将变得无效,因为调用wait()的方法将在新线程的run方法结束时自动获得控制权,即使没有调用notify()


如果我在这里犯了一个错误,那么等待有人给出一些提示。

正如其他人所指出的,这两个线程正在不同的对象上同步。因此,问题变成了如何解释主方法中的10秒延迟

请注意,如果更改
ChildThread
以删除
synchronized
块和
notifyAll()
,则会得到相同的行为

class ChildThread implements Runnable
{
    public void run()
    {
        System.out.println(this);
//        synchronized (this)
//        {
            try
            {
//                MiscTest.print("before thread notifyAll in CHILD");
//                notifyAll();
//                MiscTest.print("notifyAll over, sleep starts in CHILD");
                Thread.sleep(5000);
                MiscTest.print("after thread sleep in CHILD");

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

这表示当
线程
结束时,它自己对
线程
对象执行隐式的
notifyAll()
,并且允许专门在
线程
对象上等待的任何其他线程继续。我找不到任何说明这一点的文档,但很明显这就是正在发生的事情。

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


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

这里有两个问题:

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

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


  • 根据其他答案的建议,这里是一个可行的实现。请注意,我还将睡眠移到了
    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");
            }
        }
    }
    

    您没有在同一对象上同步。主线程在
    ct
    上,这是
    线程
    ,而
    子线程
    上同步,这是
    子线程
    。非常有趣。当然,主线程应该永远继续等待,因为没有任何东西会调用它正在等待的对象上的
    notify
    。我怀疑(但没有找到任何文档)当线程结束时,它会隐式地调用其
    线程
    对象上的
    notifyAll()
    。在
    线程
    对象本身上同步的想法有点奇怪。您在等待什么条件?在循环中等待条件。此外,在多线程的情况下,同步也很有意义。感谢您的回复。完整的解决方案已由纪尧姆发布在下面。睡眠需要放在同步块之外。是的,我在等待Thread对象并从Runnable子类对象发出通知时弄错了代码。感谢您提供的解决方案。Main会被唤醒,因为
    线程完成@SotiriosDelimanolis时会收到通知。这就是
    Thread.join()
    方法的工作原理。然而,这不应该被依赖。@gray谢谢,我就是这么想的。我试图在代码中找到这个,但我找不到。是本地制作的吗?是的@SotiriosDelimanolis。通知是由底层JVM代码生成的。谢谢你们@Gray。非常有趣。我不知道实现的细节。您可以最小化差距,但实际上您应该在
    synchronized
    块中测试条件,而不信任调用notify的线程的计时。非常感谢您的帮助。非常感谢。您可以添加一行解释,说明您已将睡眠置于同步块之外。这就是解决办法。无论如何,非常感谢。对,我只是补充了一点解释。谢谢你的建议。