题 wait()和sleep()之间的区别


a之间有什么区别? wait() 和 sleep() 在线程?

是我的理解吗? wait()-ing Thread仍处于运行模式并使用CPU周期但是a sleep()-ing不消耗任何CPU周期正确吗?

为什么我们有   wait() 和 sleep():他们的实施如何在较低的水平上变化?


1028
2018-06-24 06:48


起源


非常好的问题。两者的语义都容易混淆。 - Andreas Petersson
非常好的问题,但它们是二合一的。为什么我们两者都不同,他们可以(而不是!)在较低级别实施。我也回答过这个问题。 - estani
假设线程A在同步块中,并且当它在cpu中从此线程获取并被提供给另一个线程B.现在在线程A将进入的状态,等待此同步块的其他线程现在进入? - Peter
这是一篇描述它的好文章: qat.com/using-waitnotify-instead-thread-sleep-java - Triton Man
它的EXCATLY恰好相反 - 睡眠“使用”它所有可用的CPU周期,但由于线程将处于“等待”状态 - 这些可以在必要时产生 - 事实上大多数操作系统会自动产生周期 如果 它是可能的,因此你的线程不会创建任何实际的CPU负载......但它会在较旧的操作系统上执行此操作。另一方面,Object.wait() 决不 使用任何周期(虽然未被注意),因为在很多情况下通过软件中断实现 - 由JVM实现的私有,瞬态和透明锁。 Thread.sleep是不好的做法。 - specializt


答案:


一个 wait 可以被另一个线程调用“唤醒” notify 在正在等待的监视器上而a sleep 不能。也 wait (和 notify)必须发生在一个街区 synchronized 在监视器对象上 sleep 才不是:

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

此时,当前正在执行的线程等待 并释放显示器。另一个线程可能会做

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

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

你也可以打电话 notifyAll 如果监视器上有多个线程正在等待 - 这将被唤醒 所有这一切。但是,只有一个线程能够抓住显示器(请记住 wait 是在一个 synchronized 阻止)并继续 - 其他人将被阻止,直到他们可以获得监视器的锁定。

另一点是你打电话 wait 上 Object 本身(即你在对象的监视器上等待),而你打电话 sleep 上 Thread

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

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

739
2018-06-24 06:50



睡眠线程也可以通过notify()唤醒。 ? - Geek
不,它不能。它只能被打断。 - Peter Štibraný
@Geek - 为什么世界上你说wait()会浪费CPU周期? - Robert Munteanu
中断旨在作为一种机制,轻轻地鼓励线程完全停止运行并取消剩余的操作。 wait/notify 通常用于等待某个其他线程完成任务,或等待直到满足某个条件。 - Louis Wasserman
我仔细阅读了所有的答案,但我仍然觉得有点缺少信息。许多人写下了Javadoc中的定义以及两个英语单词的含义,但我不明白为什么我应该使用睡眠而不是等待?两者之间的基准和速度差异是什么?如果我可以做我能用睡眠做的一切,我为什么要选择睡眠呢? - Balazs Zsoldos


尚未提到的一个关键区别是,在睡眠线程时会这样做  释放它所持有的锁,同时等待释放对象上的锁 wait() 被召唤。

synchronized(LOCK) {
    Thread.sleep(1000); // LOCK is held
}


synchronized(LOCK) {
    LOCK.wait(); // LOCK is not held
}

285
2018-06-24 07:06



等待只会释放您对象的锁定 呼叫 等着。它没有发布任何 其他 锁。 - Jon Skeet
你实际上并不需要在锁内调用睡眠 - 锁和等待/通知齐头并进,但锁和睡眠是无关的。 - oxbow_lakes
@oxbow_lakes - 我会说你不应该用锁睡觉,很少有用例。只想指出差异。 - Robert Munteanu
@RobertMunteanu,你的答案误导性地声称 sleep 持有 java的 锁,但它没有。为了进行公平的比较,我们会进行比较 synchronized(OUTER_LOCK){ Thread.sleep(1000); } 同 synchronized(OUTER_LOCK){ synchronized(LOCK){LOCK.wait();} } 我们可以看到两条指令都没有发布 OUTER_LOCK。如果有任何差异,我们可以这么说 sleep 没有明确说明 使用  java的 锁,但问题是询问“他们的实施如何在较低的水平上变化?”引文结束。 - Pacerier
@Pacerier wait() 在你的代码示例中,它与调用它的内部最大锁的条件相关联, wait() 只能发布 LOCK 并不是 OUTER_LOCK。无论如何,这就是Java监视器的设计方式。公平的比较是 synchronized(OUTER_LOCK){ synchronized(LOCK) { Thread.sleep(1000); } } 和 synchronized(OUTER_LOCK){ synchronized(LOCK) { LOCK.wait(); } }。在这种情况下 sleep() 将同时保持两个锁 wait() 会释放 LOCK 但仍然坚持 OUTER_LOCK - danze


我发现 这个链接 有用(哪些参考 这个帖子)。它把它们区别开来 sleep()wait(),和 yield() 在人类方面。 (如果链接已经死了,我已将下面的帖子包含在附加标记中)

这最终都归结为操作系统的调度程序   将时间片分发给进程和线程。

sleep(n) 说 “我已完成了我的时间片,请不要给我   另一个至少n毫秒。“ 操作系统甚至没有尝试过   安排睡眠线程,直到请求的时间过去。

yield() 说 “我已完成了我的时间片,但我仍然有工作要做   做。” 操作系统可以自由地立即给线程另一个时间片,   或者给一些其他线程或处理CPU的屈服线程   只是放弃了。

.wait() 说 “我完成了我的时间片。别给我另一个   timeslice直到有人调用notify()。“ 和。一样 sleep(),操作系统不会   甚至尝试安排你的任务,除非有人打电话 notify() (或其中一个   发生了一些其他的唤醒场景)。

线程在执行时也会丢失剩余的时间片   在其他一些情况下阻止IO。如果一个线程工作   通过整个时间片,操作系统强制控制大致如同   如果 yield()已被调用,以便其他进程可以运行。

你很少需要 yield(),但如果你有一个计算量大的应用程序   逻辑任务边界,插入一个 yield()  威力 改善系统   响应性(以时间为代价 - 上下文切换,甚至只是   到操作系统和返回,不是免费的)。衡量并测试你的目标   一如既往地关心。


199
2017-08-05 19:32



收益率基本上取决于平台...... javamex.com/tutorials/threads/yield.shtml - Pacerier
解释 sleep(n) 隐含地说当前正在运行的线程自动放弃锁的监视器,这是 不对。引用自 线程的javadoc:“线程不会失去任何监视器的所有权。” - Clint Eastwood
@Jonathan在答案中没有提到显示器,那是因为 sleep 与任何其他Java方法调用相比,它没有任何关于监视器的特殊行为,也就是说,它不会以任何方式交互或修改它们。如果您想说一下监视器,您应该指定它 wait 除了上面提到的事情之外,还会暂时放弃对它所调用的对象的锁定。 - pqnet
通知如何在OS调度程序级别工作? notify是否使用特定的线程id调用某种事件处理程序,允许调度程序将相关的线程放回到正在运行的队列中?另外我还有另一个问题,螺旋锁的概念在哪里?它只与睡眠相关还是等待自己在非常低的水平使用自旋锁? - CMCDragonkai


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

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

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

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

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

它们可以在底层操作系统中以相同的方式实现,或者根本不实现(因为以前版本的Java没有真正的多线程;可能一些小型虚拟机也没有这样做)。不要忘记在VM上运行Java,因此您的代码将根据其运行的VM / OS / HW进行不同的转换。


64
2018-04-19 10:38





在这里,我列出了几个重要的区别 wait() 和 sleep() 方法。
PS:  同时点击链接查看库代码(内部工作,只需稍微玩一下以便更好地理解)。 

等待()

  1. wait() 方法释放锁。
  2. wait() 是方法 Object 类。
  3. wait() 是非静态方法 - public final void wait() throws InterruptedException { //...}
  4. wait() 应该通知 notify() 要么 notifyAll() 方法。
  5. wait() 需要从循环中调用方法以处理误报。

  6. wait() 必须从同步上下文(即同步方法或块)调用方法,否则它将抛出 IllegalMonitorStateException

睡觉()

  1. sleep() 方法不释放锁。
  2. sleep() 是方法 java.lang.Thread 类。
  3. sleep() 是静态方法 - public static void sleep(long millis, int nanos) throws InterruptedException { //... }
  4. 在规定的时间后, sleep() 完成了。
  5. sleep() 最好不要从循环中调用(即 见下面的代码)。
  6. sleep() 可以从任何地方调用。没有具体要求。

参考: 等待和睡眠之间的区别

用于调用wait和sleep方法的代码片段

synchronized(monitor){
    while(condition == true){ 
        monitor.wait()  //releases monitor lock
    }

    Thread.sleep(100); //puts current thread on Sleep    
}

thread transition to different thread states


44
2017-12-28 06:18



通过调用notify()可以唤醒睡眠线程是否正确?这里的一些其他帖子似乎暗示睡眠线程不能被唤醒但被打断。 - berimbolo
是, Thread.sleep() 用于使处理器时间可用于其他线程。睡眠周期可以通过中断(即JVM)终止。读这个 stackoverflow.com/questions/4264355/... - roottraveller
该帖还说trunk()是什么唤醒了一个睡眠线程?我指的是你发布的线程状态图,它表示notify或notifyAll将一个休眠(不等待)线程带回准备运行。我只是想确保我明白这一点。 - berimbolo
@berimbolo notify() 要么 notifyAll() 是 Object 类方法。因此,他们可以使用所有类别的obj(即 Thread 班级)。看到代码 grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/... - roottraveller
好的我需要阅读更多关于线程调度的内容,因为我找不到notify()或notifyAll()唤醒休眠线程的示例,只有interrupt()执行此操作。所有示例都将notify()和notifyAll()与等待某个监视器对象的线程相关联。 - berimbolo


在完成等待和睡眠之后,我总结了一些不同的关键注释,首先使用wait()和sleep()查看示例:

例1:使用 等待()和 睡觉():

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();
}

让清晰一些关键的笔记:

  1. 打电话
    • wait():调用持有HandObject Object的当前线程
    • sleep():调用Thread执行任务get beer(是类方法对当前运行的线程有影响)
  2. 同步
    • wait():当同步多线程访问同一个Object(HandObject)时(需要在多个线程之间进行通信(线程执行编码,线程执行获取啤酒)访问同一个对象HandObject)
    • sleep():等待条件继续执行(等待啤酒可用)
  3. 保持锁定
    • wait():释放其他对象的锁有机会执行(HandObject是免费的,你可以做其他工作)
    • sleep():保持锁定至少t次(或直到中断)(我的工作仍未完成,我继续保持锁定并等待某些条件继续)
  4. 唤醒条件
    • wait():直到从对象调用notify(),notifyAll()
    • sleep():直到至少时间到期或调用中断
  5. 最后一点是 使用的时候 如 estani 表明:

你通常使用sleep()进行时间同步和wait()   多线程同步。

如果我错了,请纠正我。


28
2018-05-19 06:59





wait()和sleep()之间的区别

  • 根本区别在于 wait() 来自 Object 和 sleep() 是静态的方法 Thread

  • 主要区别在于 wait() 释放锁定 sleep() 在等待时不释放任何锁定。

  • wait() 用于线程间通信 sleep() 通常用于在执行时引入暂停。

  • wait() 应该从内部同步调用,否则我们得到 IllegalMonitorStateException  而 sleep()  可以随便打电话

  • 再次启动线程 wait(),你必须打电话 notify() 要么 notifyAll()。而在 sleep(), 线程在指定的ms / sec间隔后启动。

相似之处有助于理解

  • 两者都让当前的线程进入了 不可运行 州。
  • 两者都是 native 方法。

21
2017-07-24 06:48





这是一个非常简单的问题,因为这两种方法都有完全不同的用法。

主要区别在于等待释放锁或监视器,而等待时睡眠不释放任何锁或监视器。等待用于线程间通信,而休眠用于在执行时引入暂停。 

这只是一个清晰而基本的解释,如果你想要更多,那么继续阅读。

的情况下 wait() 方法线程进入等待状态,在我们调用之前它不会自动返回 notify() 方法(或 notifyAll() 如果你有超过一个线程处于等待状态,你想要唤醒所有这些线程)。并且您需要同步或对象锁或类锁来访问 wait() 要么 notify() 要么 notifyAll() 方法。还有一件事, wait() 方法用于线程间通信,因为如果线程进入等待状态,您将需要另一个线程来唤醒该线程。

但是如果是的话 sleep() 这是一种方法,用于将过程保持几秒钟或您想要的时间。因为你不需要挑衅任何 notify() 要么 notifyAll() 获取该线程的方法。或者您不需要任何其他线程来回调该线程。就像你想要的东西应该在几秒钟之后发生,比如在用户轮到你想让用户等到电脑播放之后的游戏中你就可以提到 sleep() 方法。

还有一个在采访中经常被问到的重要区别: sleep() 属于 Thread 上课和 wait() 属于 Object 类。

这些都是之间的差异 sleep() 和 wait()

并且两种方法之间存在相似性:它们都是检查语句,因此您需要尝试catch或throws来访问这些方法。

我希望这能帮到您。


18
2018-04-19 07:02





资源 : http://www.jguru.com/faq/view.jsp?EID=47127

Thread.sleep() 将当前线程发送到 “不可运行” 州   一段时间。该线程保留了它所获得的监视器    - 即如果线程当前处于同步块或方法中,则其他线程不能进入该块或方法。如果另一个线程调用 t.interrupt() 它会唤醒睡眠线程。

请注意,sleep是一种静态方法,这意味着它总是会影响   当前线程(正在执行sleep方法的线程)。一个   常见的错误就是打电话 t.sleep() 其中t是不同的线程;   即使这样,它是当前线程将睡眠,而不是t线程。

t.suspend() 已弃用。使用它可以停止其他线程   比当前的线程。挂起的线程会保留所有监视器和   由于这种状态不可中断,因此容易出现死锁。

object.wait() 将当前线程发送到 “不可运行” 州,   喜欢 sleep(),但扭曲。在对象上调用Wait,而不是   线;我们称这个对象为“锁定对象”。之前 lock.wait() 是   调用时,当前线程必须在锁定对象上同步; wait()   然后释放此锁,并将线程添加到“等待列表”   与锁相关联。以后,另一个线程可以同步   相同的锁定对象和调用 lock.notify()。这唤醒了原作,   等待线程。基本上, wait()/notify() 就好像    sleep()/interrupt(),只有活动线程不需要直接   指向休眠线程的指针,但仅指向共享锁对象。


16
2017-11-05 03:34





等待和睡眠是两回事:

  • sleep() 线程停止工作指定的持续时间。
  • wait() 线程停止工作,直到通知其他线程通知等待对象。

14
2018-06-24 06:53



等待不会浪费CPU周期。 - Peter Štibraný
@Peter - 我认为确实如此。它等待()处理其CPU周期大块,然后OS将CPU周期提供给其他线程。我认为这可能取决于操作系统,我不确定。 - Geek
如果浪费CPU周期,那么wait()的实现将非常糟糕。 wait / notify用于非线程通信。 - Peter Štibraný
伙计,你是对的:-) - Geek
@Pacerier这两个结构用于不同的目的。如果您希望线程在您使用的固定时间内停止 sleep,如果你想让它停止,直到某些输入来自你使用的另一个 wait/notify。 interrupt 用于表示线程应该停止执行它正在执行和终止的操作。它由处理 sleep, wait 但也阻塞了I / O函数(你可以通过调用方法来实现具有相同行为的函数 Thread.interrupted())。至于性能,功能通常针对他们设计的目标进行优化。 - pqnet


sleep 是一种方法 Threadwait 是一种方法 Object所以 wait/notify 是一种在Java中同步共享数据的技术(使用 监控),但是 sleep 是一种简单的线程暂停方法。


11
2017-10-30 22:46