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

时间:2013-12-02 17:50:54

标签: 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 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毫秒时出现在wait()中。

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

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

如果在调用notify()时wait()不会结束,那么对notify()的需求就变成了void,因为调用wait()的方法会在新线程的run方法结束时自动获得控制权,即使没有调用notify()。

如果我在这里犯了错误,等待某人投光。

4 个答案:

答案 0 :(得分:3)

问题是您正在通知并等待不同的对象。您wait()Thread方法中的run() this ChildThread ChildThread ... Thread


您错误地命名了Runnable课程这一事实掩盖了这一点。该名称​​暗示它是{{1}}子类,但它实际上是{{1}}子类。

答案 1 :(得分: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");
        }
    }
}

答案 2 :(得分:0)

正如其他人所说,两个线程正在同步不同的对象。所以问题就变成了如何解释主方法中的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");
//        }
    }

这表明,当Thread结束时,它会在其自己的notifyAll()对象上执行隐式Thread,并且在Thread对象上专门等待的任何其他线程都是允许继续我无法找到任何说明这一点的文件,但显然正是发生了什么。

答案 3 :(得分:0)

这里有两个问题:

  1. 等待并通知对相同对象和同步块内的同步块进行调用。你的不同。一个是在名为ct的thead上,另一个是在ChildThread类型的Runnable上。

  2. 你在等待之前打电话开始。在主线程开始等待之前,很可能会调用notify。所以你可能会错过通知。在修复第1点之后,尝试调整代码,以便最小化等待和通知间隙。