线程中的wait()和sleep()有什么区别?

我是否理解wait()-ing线程仍然处于运行模式并使用CPU周期,但sleep()-ing不消耗任何CPU周期正确?

为什么我们同时使用wait()和sleep()?

它们的实现在较低级别上有什么不同?


当前回答

具有超时值的Wait()可以在超时值消失时唤醒或通知较早的(或中断), 然而,sleep()在超时值消失时被唤醒或中断,以较早的时间为准。没有超时值的Wait()将一直等待直到通知或中断。

其他回答

应该从同步块调用:wait()方法总是从同步块调用,即wait()方法需要在调用它的对象之前锁定对象监视器。但是sleep()方法可以从外部同步块调用,即sleep()方法不需要任何对象监视器。

IllegalMonitorStateException:如果wait()方法被调用而没有获得对象锁,则IllegalMonitorStateException在运行时抛出,但sleep()方法从不抛出此类异常。

属于哪个类:wait()方法属于java.lang.Object类,sleep()方法属于java.lang.Thread类。

在对象或线程上调用:wait()方法在对象上调用,而sleep()方法在线程上调用,而不是在对象上。

线程状态:当在对象上调用wait()方法时,持有对象监视器的线程从运行状态变为等待状态,只有在该对象上调用notify()或notifyAll()方法时才能返回到可运行状态。然后线程调度程序将线程从可运行状态调度到运行状态。 当sleep()在线程上被调用时,它会从运行状态转到等待状态,并在休眠时间结束时返回到可运行状态。

从同步块调用时:当wait()方法被调用时,线程离开对象锁。但是sleep()方法在从同步块或方法线程调用时不会留下对象锁。

更多参考资料

wait()和sleep()的区别

最根本的区别是wait()是Object的非静态方法,sleep()是Thread的静态方法。 主要的区别是wait()释放锁,而sleep()在等待时不释放任何锁。 Wait()用于线程间通信,而sleep()通常用于在执行时引入暂停。 wait()应该从synchronise内部调用,否则我们会得到一个IllegalMonitorStateException,而sleep()可以在任何地方调用。 要从wait()再次启动线程,必须无限期地调用notify()或notifyAll()。至于sleep(),线程肯定会在指定的时间间隔后启动。

相似之处

两者都使当前线程进入不可运行状态。 两者都是本机方法。

一个等待线程可以被另一个调用正在被等待的监视器上的notify线程“唤醒”,而一个睡眠线程则不能。另外,一个wait(和notify)必须发生在monitor对象上同步的块中,而sleep则不会:

Object mon = ...;
synchronized (mon) {
    mon.wait();
} 

此时,当前正在执行的线程等待并释放监视器。另一个线程可以

synchronized (mon) { mon.notify(); }

(在同一个mon对象上)和第一个线程(假设它是在监视器上等待的唯一线程)将被唤醒。

如果有多个线程在监视器上等待,您也可以调用notifyAll—这将唤醒所有线程。但是,只有一个线程能够获取监视器(记住,等待是在同步块中)并继续执行—其他线程将被阻塞,直到它们获得监视器的锁。

另一点是你在对象本身调用wait(即你在对象的监视器上调用wait),而你在线程上调用sleep。

还有一点是,你可以从wait中得到虚假的唤醒(例如,正在等待的线程没有明显的原因就恢复了)。你应该总是等待在某些条件下旋转,如下所示:

synchronized {
    while (!condition) { mon.wait(); }
}

wait()必须被synchronized包围,当线程进入synchronized块或方法时,它意味着获得锁,所以它不阻塞,调用wait意味着释放锁,所以它退出synchronized然后阻塞,thread .sleep()导致当前线程在指定的时间内暂停执行。线程不会失去任何监视器的所有权

这里有很多答案,但我找不到任何一个提到的语义区别。

这与线程本身无关;这两种方法都是必需的,因为它们支持非常不同的用例。

sleep()让线程像以前一样进入睡眠状态,它只是打包上下文并在预定义的时间内停止执行。因此,为了在到期时间之前唤醒它,您需要知道Thread引用。这在多线程环境中并不常见。它主要用于时间同步(例如,在3.5秒内醒来)和/或硬编码的公平性(只睡一会儿,让其他线程工作)。

相反,wait()是一种线程(或消息)同步机制,它允许您通知没有存储引用(也没有关心)的线程。您可以将其视为一个发布-订阅模式(wait == subscribe and notify() == publish)。基本上,使用notify()你是在发送一条消息(甚至可能根本没有收到,通常情况下你并不关心)。

总而言之,通常使用sleep()进行时间同步,使用wait()进行多线程同步。

它们可以在底层操作系统中以同样的方式实现,也可以完全不实现(因为以前版本的Java没有真正的多线程;可能一些小的虚拟机也不这样做)。别忘了Java是在VM上运行的,所以你的代码会根据所运行的VM/OS/HW的不同而转换成不同的东西。