线程中的wait()
和sleep()
之间有什么区别?
我的理解是wait()
的线程仍处于运行模式且使用CPU周期但是sleep()
- 不会消耗任何CPU周期吗?
为什么我们 wait()
和sleep()
:他们的实施如何在较低的水平上变化?
答案 0 :(得分:789)
wait
可以被监视器上正在等待的另一个调用notify
的线程“唤醒”,而sleep
则不能。此外,wait
(和notify
)必须在监视器对象的块synchronized
中发生,而sleep
则不会:
Object mon = ...;
synchronized (mon) {
mon.wait();
}
此时,当前正在执行的线程等待并释放监视器。另一个线程可以做
synchronized (mon) { mon.notify(); }
(在相同的mon
对象上)和第一个线程(假设它是监视器上唯一等待的线程)将被唤醒。
如果监视器上有多个线程正在等待,您也可以调用notifyAll
- 这将唤醒所有线程。但是,只有一个线程能够抓住监视器(请记住wait
在synchronized
块中)并继续 - 其他线程将被阻止,直到他们可以获取监视器的锁定
另一点是你在Object
上呼叫wait
(即你在对象的监视器上等待),而你在Thread
上呼叫sleep
。
另一点是你可以从wait
获得虚假唤醒(即正在等待恢复的线程没有明显的原因)。你应该总是wait
在某种情况下旋转,如下所示:
synchronized {
while (!condition) { mon.wait(); }
}
答案 1 :(得分:311)
尚未提及的一个关键区别是,在休眠线程时,不释放它所持有的锁定,而等待释放对wait()
被调用的对象的锁定。
synchronized(LOCK) {
Thread.sleep(1000); // LOCK is held
}
synchronized(LOCK) {
LOCK.wait(); // LOCK is not held
}
答案 2 :(得分:222)
我发现this post很有帮助。它以人类术语表示Thread.sleep()
,Thread.yield()
和Object.wait()
之间的差异。引用:
这一切最终都归结为操作系统的调度程序 将时间片分发给进程和线程。
sleep(n)
说 “我已完成了我的时间片,请不要给我 另一个至少n毫秒。“ 操作系统甚至都没有尝试过 安排睡眠线程,直到请求的时间过去。
yield()
说 “我已完成了我的时间片,但我仍然有工作要做 做。“ 操作系统可以立即给线程另一个时间片, 或者给一些其他线程或处理CPU的屈服线程 只是放弃了。
wait()
说 “我已完成了我的时间片。不要再给我一个了 timeslice直到有人调用notify()。“ 与sleep()
一样,操作系统不会 甚至尝试安排你的任务,除非有人打电话给notify()
(或其中一个) 发生了一些其他的唤醒场景。)线程在执行时也会失去剩余的时间片 在其他一些情况下阻止IO。如果一个线程工作 通过整个时间片,操作系统强制控制大致如同 如果已调用
yield()
,则可以运行其他进程。你很少需要
yield()
,但如果你有一个计算量很大的应用程序 逻辑任务边界,插入yield()
可能改进系统 响应性(以时间为代价 - 上下文切换,甚至只是 到操作系统和返回,不是免费的)。衡量并测试你的目标 一如既往地关心。
答案 3 :(得分:65)
这里有很多答案,但我找不到任何提到的语义区别。
这不是线程本身;这两种方法都是必需的,因为它们支持非常不同的用例。
sleep()
将线程发送到之前的睡眠状态,它只是打包上下文并停止执行预定义的时间。因此,为了在到期时间之前将其唤醒,您需要知道Thread引用。这在多线程环境中不常见。它主要用于时间同步(例如,在3.5秒内唤醒)和/或硬编码公平性(只是暂时休眠并让其他线程工作)。
wait()
是一种线程(或消息)同步机制,允许您通知一个没有存储引用的线程(也不关心)。您可以将其视为发布 - 订阅模式(wait
== subscribe和notify()
==发布)。基本上使用notify()你正在发送一条消息(甚至可能根本没有收到,通常你也不在乎)。
总而言之,您通常使用sleep()
进行时间同步,使用wait()
进行多线程同步。
它们可以在底层操作系统中以相同的方式实现,或者根本不实现(因为以前版本的Java没有真正的多线程;可能一些小型虚拟机也没有这样做)。不要忘记在VM上运行Java,因此您的代码将根据其运行的VM / OS / HW进行不同的转换。
答案 4 :(得分:49)
在此,我列出了wait()
和sleep()
方法之间的一些重要差异。
PS: 同时点击链接查看图书馆代码(内部工作,只是为了更好的理解而玩一下)。
wait()
方法释放锁。 wait()
是Object
class。wait()
是非静态方法 - public final void wait() throws InterruptedException { //...}
wait()
应通过notify()
或notifyAll()
方法通知。 wait()
方法以处理误报。
wait()
方法,否则它将抛出IllegalMonitorStateException
sleep()
方法无法释放锁定。sleep()
是java.lang.Thread
class。sleep()
是静态方法 - public static void sleep(long millis, int nanos) throws InterruptedException { //... }
sleep()
完成。sleep()
最好不要从循环调用(即见下面的代码)。sleep()
。没有具体要求。 参考:Difference between Wait and Sleep
调用等待和睡眠方法的代码段
synchronized(monitor){
while(condition == true){
monitor.wait() //releases monitor lock
}
Thread.sleep(100); //puts current thread on Sleep
}
答案 5 :(得分:28)
在等待和睡眠之后,我总结了一些不同的关键注释,首先使用wait()和sleep()查看样本:
Example1 :使用等待()和睡眠():
synchronized(HandObject) {
while(isHandFree() == false) {
/* Hand is still busy on happy coding or something else, please wait */
HandObject.wait();
}
}
/* Get lock ^^, It is my turn, take a cup beer now */
while (beerIsAvailable() == false) {
/* Beer is still coming, not available, Hand still hold glass to get beer,
don't release hand to perform other task */
Thread.sleep(5000);
}
/* Enjoy my beer now ^^ */
drinkBeers();
/* I have drink enough, now hand can continue with other task: continue coding */
setHandFreeState(true);
synchronized(HandObject) {
HandObject.notifyAll();
}
明确一些关键注意事项:
你通常使用sleep()进行时间同步和wait() 多线程同步。
如果我错了,请纠正我。
答案 6 :(得分:22)
根本区别在于wait()
来自Object
而sleep()
是Thread
的静态方法。
主要区别在于wait()
释放锁定,而sleep()
在等待时不释放任何锁定。
wait()
用于线程间通信,而sleep()
用于在执行时引入暂停。
wait()
应该从内部同步调用,否则我们会得到IllegalMonitorStateException
,而sleep()
可以在任何地方调用。
wait()
再次启动主题,您必须致电notify()
或notifyAll()
。对于sleep(),
,线程在指定的时间间隔后启动。答案 7 :(得分:18)
这是一个非常简单的问题,因为这两种方法都有完全不同的用法。
主要区别在于等待释放锁定或监视器,而等待时睡眠不释放任何锁定或监视器。等待用于线程间通信,而睡眠用于在执行时引入暂停。
这只是一个清晰而基本的解释,如果你想要更多,那么继续阅读。
如果wait()
方法线程进入等待状态,它将不会自动返回,直到我们调用notify()
方法(或notifyAll()
如果你有多个线程进入等待状态,你想唤醒所有这些线程)。您需要同步或对象锁定或类锁定才能访问wait()
或notify()
或notifyAll()
方法。还有一件事,wait()
方法用于线程间通信,因为如果一个线程进入等待状态,你将需要另一个线程来唤醒该线程。
但是在sleep()
的情况下,这是一种方法,用于将过程保持几秒钟或您想要的时间。因为您不需要激发任何notify()
或notifyAll()
方法来获取该线程。或者您不需要任何其他线程来回调该线程。就像你想要的东西应该在几秒钟之后发生,比如在用户轮到游戏之后,你希望用户等到计算机播放然后你可以提到sleep()
方法。
在访谈中经常会提到一个更重要的区别:sleep()
属于Thread
类,wait()
属于Object
类。
这些是sleep()
和wait()
之间的所有差异。
两种方法之间存在相似之处:它们都是检查语句,因此您需要尝试catch或throws来访问这些方法。
我希望这会对你有所帮助。
答案 8 :(得分:16)
来源:http://www.jguru.com/faq/view.jsp?EID=47127
Thread.sleep()
将当前线程发送到" Not Runnable" 状态 一段时间。该线程保留了它所获得的监视器 - 即如果线程当前处于同步块或方法中,则其他线程无法进入该块或方法。如果另一个线程调用t.interrupt()
,它将唤醒睡眠线程。请注意,sleep是一种静态方法,这意味着它始终会受到影响 当前线程(正在执行sleep方法的线程)。一个 常见的错误是调用
t.sleep()
,其中t是不同的线程; 即便如此,它是当前正在休眠的线程,而不是t线程。
t.suspend()
已弃用。使用它可以停止其他线程 比当前的线程。挂起的线程会保留所有监视器和 由于这种状态不可中断,因此容易出现死锁。
object.wait()
将当前线程发送到" Not Runnable" 状态, 像sleep()
一样,但有一点扭曲。在对象上调用Wait,而不是 线;我们称这个对象为"锁定对象。"在lock.wait()
之前 调用时,当前线程必须在锁定对象上同步;wait()
然后释放此锁,并将该线程添加到"等待列表" 与锁相关联。以后,另一个线程可以同步 相同的锁定对象并调用lock.notify()
。这唤醒了原作, 等待线程。基本上,wait()
/notify()
就像sleep()
/interrupt()
,只有活动线程不需要直接 指向休眠线程的指针,但仅指向共享锁对象。
答案 9 :(得分:14)
等待和睡眠是两回事:
sleep()
中,线程停止工作指定的持续时间。wait()
中,线程停止工作,直到通知其他线程通知等待的对象。答案 10 :(得分:11)
sleep
是Thread
的方法,wait
是Object
的方法,因此wait/notify
是一种在Java中同步共享数据的技术(使用monitor),但sleep
是一种简单的线程暂停方法。
答案 11 :(得分:7)
sleep()是一个方法,用于将进程保持几秒或你想要的时间但是在wait()方法的情况下线程进入等待状态并且它不会来在我们调用notify()或notifyAll()之前自动返回。
主要区别是 wait()释放锁定或监视器,而sleep()在等待时不释放任何锁定或监视器。等待用于线程间通信,而睡眠用于在执行时引入暂停。
Thread.sleep()将当前线程发送到“Not Runnable”状态一段时间。线程保持它已获取的监视器 - 即,如果线程当前处于同步块或方法中,则其他线程不能进入该块或方法。如果另一个线程调用t.interrupt(),它将唤醒睡眠线程。请注意,sleep是一种静态方法,这意味着它总是会影响当前线程(正在执行sleep方法的线程)。一个常见的错误是调用t.sleep(),其中t是一个不同的线程;即便如此,它是当前正在休眠的线程,而不是t线程。
object.wait()将当前线程发送到“Not Runnable”状态,如sleep(),但有一个扭曲。在对象上调用Wait,而不是线程;我们将此对象称为“锁定对象”。在调用lock.wait()之前,当前线程必须在锁定对象上进行同步; wait()然后释放此锁,并将线程添加到与锁相关联的“等待列表”。稍后,另一个线程可以在同一个锁对象上同步并调用lock.notify()。这唤醒了原始的等待线程。基本上,wait()/ notify()就像sleep()/ interrupt(),只有活动线程不需要直接指向休眠线程的指针,而只需要指向共享锁对象。
synchronized(LOCK) {
Thread.sleep(1000); // LOCK is held
}
synchronized(LOCK) {
LOCK.wait(); // LOCK is not held
}
让我们对以上各点进行分类:
Call on:
Synchronized:
Hold lock:
Wake-up condition:
Usage:
答案 12 :(得分:6)
wait
和sleep
方法非常不同:
来考虑一下,这个名字在这方面令人困惑;但sleep
是标准名称,而wait
与Win API中的WaitForSingleObject
或WaitForMultipleObjects
类似。
答案 13 :(得分:5)
从这篇文章:http://javaconceptoftheday.com/difference-between-wait-and-sleep-methods-in-java/
1)调用wait()方法的线程释放它所持有的锁。
2)在其他线程调用同一个锁上的notify()或notifyAll()方法后,线程重新获得锁定。
3)必须在synchronized块中调用wait()方法。
4)始终在对象上调用wait()方法。
5)通过调用notify()或notifyAll()方法,其他线程可以唤醒等待线程。
6)要调用wait()方法,线程必须有对象锁。
1)调用sleep()方法的线程不会释放它所持有的锁。
2)sleep()方法可以在synchronized块内外调用。
3)总是在线程上调用sleep()方法。
4)其他线程无法唤醒睡眠线程。如果这样做,线程将抛出InterruptedException。
5)要调用sleep()方法,线程不需要对象锁定。
答案 14 :(得分:5)
简单来说,wait is wait直到某个其他线程调用你,而sleep在某段指定的时间内“不执行下一个语句”。
此外,sleep是Thread类中的静态方法,它在线程上运行,而wait()在Object类中并在对象上调用。
另一点,当你在某个对象上调用wait时,所涉及的线程会同步对象然后等待。 :)
答案 15 :(得分:4)
睡眠/中断和等待/通知之间的一个潜在的巨大差异是
interrupt()
期间调用sleep()
始终会抛出异常(例如InterruptedException),而notify()
期间拨打wait()
没有。在不需要时生成异常是低效的。如果你的线程以高速率相互通信,那么如果你一直在调用中断,那就会产生很多例外,这完全是浪费CPU。
答案 16 :(得分:4)
wait()
是Object
类的方法
sleep()
是Thread
类的方法。
sleep()
允许线程进入sleep
状态x毫秒。
当线程进入睡眠状态it doesn’t release the lock
时。
wait()
允许线程释放锁定goes to suspended state
当notify()
或notifAll()
方法为时,此主题将处于活动状态
要求使用相同的对象。
答案 17 :(得分:3)
这里wait()将处于等待状态,直到它被另一个线程通知但是sleep()将在哪里有一些时间......之后它会自动转移到Ready状态......
答案 18 :(得分:3)
等待()和睡眠()差异?
Thread.sleep()方法 一旦它的工作完成,那么只有它释放锁定给每个人。直到永远不会向任何人发布锁定。
Sleep() take the key, its never release the key to anyone, when its work completed then only its release then only take the key waiting stage threads.
的Object.wait() 当它进入等待阶段时,它将释放密钥并等待基于参数的一些秒。
例如:
你右手拿着咖啡,你可以拿另一只手拿着咖啡,你什么时候放下来,然后在这里只拿另一个同类型的物品。也。这是睡眠() 你睡觉的时间没有任何工作,你只是在睡觉......也在这里。
等待()。当你在等待的时候放下你的另一个意思,等等
你是在你的系统中播放电影或任何东西,你可以一次播放不止一个播放器,这就是它在这里,当你关闭并选择另一个电影或歌曲时,叫做等待< / p>
答案 19 :(得分:3)
这些方法用于不同的事情。
Thread.sleep(5000); // Wait until the time has passed.
Object.wait(); // Wait until some other thread tells me to wake up.
Thread.sleep(n)可以被中断,但必须通知Object.wait()。
可以指定等待的最长时间:Object.wait(5000)
因此可以使用wait
,呃,sleep
但是你必须打扰锁。
这两种方法在睡眠/等待时都不使用cpu。
这些方法是使用本机代码实现的,使用类似的结构但不是以相同的方式。
自己找:Is the source code of native methods available?文件/src/share/vm/prims/jvm.cpp
是起点......
答案 20 :(得分:3)
wait
释放锁定,而sleep
则不会。处于等待状态的线程有权在调用notify
或notifyAll
后立即唤醒。但是在sleep
的情况下,线程会保持锁定,并且只有在睡眠时间结束后它才有资格。
答案 21 :(得分:3)
你是对的 - Sleep()导致该线程“休眠”并且CPU将关闭并处理其他线程(也称为上下文切换),我相信Wait会让CPU处理当前线程。
我们都有这两个因为虽然让你的其他人在你不使用它时使用CPU似乎是明智的,但实际上有一个上下文切换的开销 - 取决于睡眠的时间长短,它可能更昂贵在CPU循环中切换线程而不是让你的线程在几毫秒内什么也不做。
另请注意,sleep强制进行上下文切换。
此外 - 通常无法控制上下文切换 - 在等待操作系统期间(并且等待更长时间)可以选择处理其他线程。
答案 22 :(得分:2)
sleep()
方法使当前线程在指定时间内从运行状态移动到块状态。如果当前线程具有任何对象的锁定,则它会持续保持它,这意味着其他线程无法在该类对象中执行任何同步方法。
wait()
方法导致当前线程进入阻塞状态指定的时间或直到通知,但在这种情况下,线程释放对象的锁(这意味着其他线程可以执行任何同步的方法调用对象。
答案 23 :(得分:2)
在我看来,两种机制之间的主要区别在于睡眠/中断是处理线程的最基本方式,而 wait / notify是一种旨在简化线程间通信的抽象。这意味着睡眠/中断可以做任何事情,但这个特定任务更难做到。
为什么等待/通知更合适?以下是一些个人考虑因素:
它强制集中。它允许协调一组线程与单个共享对象之间的通信。这大大简化了工作。
它强制执行同步。因为它使程序员在同步块中包含对wait / notify的调用。
它与线程来源和编号无关。使用这种方法,您可以任意添加更多线程,而无需编辑其他线程或跟踪现有线程。如果您使用了sleep / interrupt,首先需要保留对休眠线程的引用,然后手动逐个中断它们。
现实生活中的一个例子很好地解释了这是一个经典的餐厅和人员用来沟通的方法:服务员将客户的要求留在中央位置(软木板,桌子等) 。),敲响钟声,来自厨房的工人来接受这样的要求。一旦准备好任何课程,厨房工作人员再次响铃,以便服务员知道并将它们带给顾客。
答案 24 :(得分:2)
关于睡眠的示例不释放锁定并等待
这里有两个类:
Singleton :这是具有两个静态方法getInstance()和getInstance(boolean isWait)的单例类。
public class Main {
private static Singleton singletonA = null;
private static Singleton singletonB = null;
public static void main(String[] args) throws InterruptedException {
Thread threadA = new Thread() {
@Override
public void run() {
singletonA = Singleton.getInstance(true);
}
};
Thread threadB = new Thread() {
@Override
public void run() {
singletonB = Singleton.getInstance();
while (singletonA == null) {
System.out.println("SingletonA still null");
}
if (singletonA == singletonB) {
System.out.println("Both singleton are same");
} else {
System.out.println("Both singleton are not same");
}
}
};
threadA.start();
threadB.start();
}
}
和
public class Singleton {
private static Singleton _instance;
public static Singleton getInstance() {
if (_instance == null) {
synchronized (Singleton.class) {
if (_instance == null)
_instance = new Singleton();
}
}
return _instance;
}
public static Singleton getInstance(boolean isWait) {
if (_instance == null) {
synchronized (Singleton.class) {
if (_instance == null) {
if (isWait) {
try {
// Singleton.class.wait(500);//Using wait
Thread.sleep(500);// Using Sleep
System.out.println("_instance :"
+ String.valueOf(_instance));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
_instance = new Singleton();
}
}
}
return _instance;
}
}
现在运行此示例,您将获得以下输出:
_instance :null
Both singleton are same
这里threadA和threadB创建的Singleton实例是相同的。这意味着threadB在外面等待,直到threadA释放它为止。
现在通过注释Thread.sleep(500)来更改Singleton.java;方法和取消注释Singleton.class.wait(500); 。这是因为Singleton.class.wait(500);方法threadA将释放所有获取锁并进入“Non Runnable”状态,threadB将进入更改以进入synchronized块。
现在又跑了:
SingletonA still null
SingletonA still null
SingletonA still null
_instance :com.omt.sleepwait.Singleton@10c042ab
SingletonA still null
SingletonA still null
SingletonA still null
Both singleton are not same
此处由threadA和threadB创建的Singleton实例不相同,因为threadB已更改为在synchronized块中输入,并且在500毫秒后threadA从其最后位置开始并再创建一个Singleton对象。
答案 25 :(得分:2)
来自Object
的{{3}}方法的oracle文档页面:
public final void wait()
notify()
方法或notifyAll()
方法。换句话说,此方法的行为就像它只是执行调用wait(0)
。此方法抛出
IllegalMonitorStateException
- 如果当前线程不是对象监视器的所有者。
InterruptedException
- 如果任何线程在当前线程等待通知之前或当前线程中断当前线程。抛出此异常时,将清除当前线程的中断状态。
来自Thread
类的wait()方法的oracle文档页面:
public static void sleep(long millis)
此方法抛出:
IllegalArgumentException
- 如果millis的值为负
InterruptedException
- 如果有任何线程中断了当前线程。抛出此异常时,将清除当前线程的中断状态。
其他关键区别:
与静态方法wait()
(类方法)不同, sleep()
是一种非静态方法(实例方法)。
答案 26 :(得分:1)
实际上,Java文档中清楚地描述了所有这些(但我只是在阅读完答案后才意识到这一点)。
http://docs.oracle.com/javase/8/docs/api/index.html:
wait() - 当前线程必须拥有此对象的监视器。线程发布 此监视器的所有权,并等待另一个线程通知 在这个对象的监视器上等待通过a唤醒的线程 调用notify方法或notifyAll方法。线程然后 等到它可以重新获得监视器的所有权并继续执行。
sleep() - 使当前正在执行的线程休眠(暂时停止执行)指定的毫秒数,具体取决于系统定时器和调度程序的精度和准确性。该线程不会失去任何监视器的所有权。
答案 27 :(得分:1)
wait(1000)
导致当前线程休眠最多一秒。
notify()
或notifyAll()
方法调用,则可以在不到1秒的时间内休眠。sleep(1000)
的调用会导致当前线程暂停正好1秒。
答案 28 :(得分:1)
等待超时值可以在超时值超时后唤醒或通知较早者(或中断),然后,睡眠时间超过超时值时唤醒或中断较早者。没有超时值的wait()将等待直到通知或中断
答案 29 :(得分:1)
wait()
在同步方法中给出
而sleep()
是在非同步方法中给出的,因为wait()
方法会释放对象的锁定,但sleep()
或yield()
会释放lock()
。
答案 30 :(得分:0)
让我们假设你正在听歌。
只要当前的歌曲正在播放,下一首歌就不会播放,即下一首歌调用Sleep()
如果你完成了歌曲,它将停止,直到你选择播放按钮(notify())它不会播放,即当前歌曲调用的wait()。
在这两种情况下歌曲都会进入等待状态。
答案 31 :(得分:0)
wait()必须被同步包围,当线程进入同步块或方法时,这意味着获得了锁,因此它没有被阻塞,调用等待意味着释放了锁,因此退出了同步然后块Thread.sleep。 ()导致当前线程在指定的时间段内暂停执行。该线程不会失去任何监视器的所有权