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的线程的计时。非常感谢您的帮助。非常感谢。您可以添加一行解释,说明您已将睡眠置于同步块之外。这就是解决办法。无论如何,非常感谢。对,我只是补充了一点解释。谢谢你的建议。