Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/372.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.lang.Object.wait()的不同行为_Java_Wait_Notify - Fatal编程技术网

java.lang.Object.wait()的不同行为

java.lang.Object.wait()的不同行为,java,wait,notify,Java,Wait,Notify,我试图使用java.lang.Object.wait()方法,并编写了3个不同的示例代码,其中我得到了wait()方法的不同行为 样本1) 样本3) 在样本1中) main线程将永远处于等待状态正如它调用的b.wait()方法一样,并且在对象b上没有线程提供notify()或notifyAll()。在调用b.wait()方法的main线程之前,已经终止了子线程。 这个输出是我所期望的 在样本2中) main线程在打印后处于等待状态10秒(t.wait(10000);) X 开始等待 10秒后,m

我试图使用
java.lang.Object.wait()
方法,并编写了3个不同的示例代码,其中我得到了
wait()
方法的不同行为

样本1)

样本3)

在样本1中)

main线程将永远处于等待状态正如它调用的
b.wait()
方法一样,并且在对象
b
上没有线程提供
notify()
notifyAll()
。在调用
b.wait()
方法的main线程之前,已经终止了子线程。 这个输出是我所期望的

在样本2中)

main线程在打印后处于等待状态10秒(
t.wait(10000);
) X
开始等待
10秒后,main线程执行
等待t
Y
这也是我的预期输出

在样本3中)

main线程未处于等待状态(
t.wait(10000);
),即使在调用
t.wait(10000)的main线程时子线程肯定已被终止
那么它为什么不等待呢?并立即执行
开始等待
等待t
Y

这不是我的预期输出。

对于前两个例子,您的预期似乎是正确的。在第三个示例中,可以合理地预期t将在主线程开始等待之前完成,然后主线程将挂起直到超时

但正如你所观察到的,事情并非如此

等待线程不会停止等待,除非被中断或通知(虚假唤醒除外,但这些都是不可预测的竞争条件的结果;发布的代码中的行为发生可靠,因此我认为这里可以排除虚假唤醒)

由于没有任何东西会中断主线程,并且它的等待被缩短,并且我们已经排除了虚假的唤醒,因此它必须接收到通知。只有一种东西可以提供通知,那就是t线程

要让t通知主线程,它必须在t开始等待时处于活动状态。那么,是什么让它继续存在

当线程终止时,会发生一些不为人所知的行为。报告说:

此实现使用This.wait调用的循环,该循环以This.isAlive为条件。当线程终止时,调用this.notifyAll方法。建议应用程序不要在线程实例上使用wait、notify或notifyAll

发生的情况是:

1) t打印其输出,并且正在退出其run方法

2) 在t和主线程之间有一个座圈以获得t上的锁。t需要它调用notifyAll,main需要它进入synchronized块。主线程碰巧先抓住锁

3) 它会一直呆在那里直到它能拿到锁

4) 主线程进入等待方法(释放锁)

5) t获取锁并调用t.notifyAll

5) 主线程收到通知并离开等待方法(重新获取锁)

一些教训:

  • 不要在线程上进行同步(这是一个很好的例子,说明了为什么API文档说不要这样做,在这里,您无意中延迟了一个线程,使其不能及时死亡)

  • 如果线程没有等待,则不会得到通知。如果线程在通知发生后开始等待,则该通知将丢失

  • 不要仅仅依赖于通知(这会使您的代码容易受到竞争条件的影响),而是将通知与其他线程可以设置的条件一起使用。使用测试条件在循环中调用wait。如果您看到Thread.join源代码,这是一个很好的示例,它看起来像:

        while (isAlive()) {
            wait(0);
        }
    
  • 不要拿着锁睡觉。它使系统响应速度降低,但没有任何好处

  • 对事情发生的顺序进行假设时要非常小心


您不应该在线程实例上同步,也不应该将其用作监视器。它让人困惑,而且它不做你认为它做的事情,而且它可能与线程的内部结构冲突。@AdriaanKoster-我知道synchronized关键字的作用。这是学习wait()方法工作的示例代码。正如Mark所说,不要在线程对象上同步。在任何其他对象上同步(我建议
new object()
)并在该对象上调用
wait()
,将使您的
wait
调用按预期进行。@Nathanhues请在您的答案部分查看我的评论。Thanks@Nathan-你说的是矛盾的话。。。“发生的事情是t打印其输出,然后主线程抓住锁,直到主线程等待(释放锁),t才有机会拿回它。对于t,它需要调用notifyAll,如果不获取自己的锁,它就不能这样做。它会阻塞,直到能够获取锁。”正如上面的行所示。。线程t获取其锁并调用notifyAll(),然后在main方法释放锁后终止。但实际上这就是问题所在,主线程甚至没有等待(t.wait(10000);@raven03:main线程调用wait。notifyAll生效时,等待被缩短,这导致线程从等待中返回。当然,它需要重新获取锁才能做到这一点,但是在调用notifyAll之后,它不会释放锁,所以锁是可用的。不清楚什么是矛盾的。@NathanHughes您如何解释下面程序的输出--public class Main{public static void Main(String[]args)抛出InterruptedException{Thread t=new Thread(){public void run(){System.out.println(“我是第二个线程”);};t.start();System.out.println
public class Main{
public static void main (String[] args) throws InterruptedException {
    Thread t = new Thread();    
    t.start();
    System.out.println("X"); //--> 1
    synchronized(t) { 
    System.out.println("starting to wait"); //--> 2
    t.wait(10000);
    System.out.println("waiting on t"); //--> 3
    }
    System.out.println("Y"); //--> 4
   }
}
public class Main{
public static void main (String[] args) throws InterruptedException {
     Thread t = new Thread() {public void run() 
                     {System.out.println("I am the second thread.");}};
     t.start();
     System.out.println("X"); //--> 1
     synchronized(t) { 
         Thread.sleep(4000);
         System.out.println("starting to wait"); //--> 2
         t.wait(10000);
         System.out.println("waiting on t"); //--> 3
     }
     System.out.println("Y"); //--> 4
  }
}
    while (isAlive()) {
        wait(0);
    }