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


1203

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

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

我们为什么同时 拥有wait()sleep():它们的实现在较低的水平如何变化?


50
很好的问题。两者的语义都很容易混淆。
Andreas Petersson,2009年

1
非常好的问题,但它们是二合一的。为什么我们两者都与在较低级别可以(也不能被实现)的方式不同。我也已经回答了。
estani 2012年

假设一个线程A在一个同步块中,并且在从该线程进入cpu的同时,将其分配给另一个线程B。现在线程A进入哪种状态,等待此同步块的其他线程现在是否会进入内部?
彼得

1
这是一篇描述它的好文章:qat.com/using-waitnotify-instead-thread-sleep-java
Triton Man

3
它的情况恰好相反-睡眠“使用”了所有可用的CPU周期,但是由于线程将处于“等待”状态,因此可以在必要时产生这些-实际上,如果可能,大多数操作系统会自动产生这些周期,因此您的线程不会创建任何实际的CPU负载……但是,它将在较旧的操作系统上创建。另一方面,Object.wait()绝不使用任何周期(在未通知的情况下),因为在许多情况下,这是通过软件中断来实现的-JVM实现的私有,临时和透明锁。Thread.sleep是个坏习惯。
specializt

Answers:


837

A wait可以被另一个notify正在等待等待的监视器调用的线程“唤醒” sleep。此外,wait(和notify)必须在synchronized监视对象的块中发生,而sleep不会:

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

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

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

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

您还可以notifyAll在监视器上等待多个线程的情况下进行调用-这将唤醒所有线程。但是,只有一个线程将能够抓住显示器(记住,wait是在synchronized块中)并继续运行-然后其他被阻塞,直到它们获得监视器的锁为止。

另一点是,你叫waitObject本身(即您等待对象的监视器上),而你打电话sleepThread

另一个问题是,你可以得到虚假唤醒wait(即线程正在等待简历没有明显的原因)。以下情况下,您应始终wait旋转

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

131
不,它不能。它只能被打断。
PeterŠtibraný09年

9
中断时,必须知道要中断的线程。当您调用notify时,您只需要一个对象,而不必关心该对象上是否有其他“等待”线程。等待/通知用于通信,而睡眠用于(例如)睡眠。
PeterŠtibraný09年

28
@Geek-为什么您说world()浪费CPU周期?
罗伯特·蒙提亚努

25
中断旨在作为一种机制来温和地鼓励线程完全停止运行并取消其余操作。 wait/ notify通常用于等待其他某个线程完成任务,或者等待直到满足特定条件。
Louis Wasserman

13
我通读了所有答案,但仍然感到缺少一些信息。许多人写下了Javadoc的定义以及两个英文单词的含义,但我不明白为什么我应该使用sleep而不是wait?两者之间的基准测试和速度差异是什么?如果我能做到睡眠所能做的一切,为什么我应该选择睡眠呢?
Balazs Zsoldos

334

没有提到的一个关键区别是,睡觉时一个线程并没有释放它持有,同时等待释放的对象的锁锁wait()被称为上。

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


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

105
等待仅释放对您调用 wait()的对象的锁定。它不会释放任何其他锁。
乔恩·斯基特

16
您实际上不需要从锁内部调用睡眠-锁和等待/通知并存,但是锁和睡眠无关。
oxbow_lakes

7
@oxbow_lakes-我想说你不应该带锁入睡,很少有用例。只是想指出差异。
罗伯特·蒙提亚努

5
@RobertMunteanu,您的回答有误导性,声称它sleep持有Java锁,但事实并非如此。为了进行公平的比较,我们将与进行比较synchronized(OUTER_LOCK){ Thread.sleep(1000); }synchronized(OUTER_LOCK){ synchronized(LOCK){LOCK.wait();} }我们可以看到两条指令都没有释放OUTER_LOCK。如果有任何区别,我们可以说sleep没有显式使用 Java锁,但是问题是询问报价“它们的实现在较低级别如何变化?” 取消报价。
Pacerier,2014年

2
wait()在您的代码示例中,@Pacerier 与调用它的最内部锁定的条件相关联,wait()只能释放LOCK而不能释放OUTER_LOCK。无论如何,这就是Java监视器的设计方式。一个合理的比较是synchronized(OUTER_LOCK){ synchronized(LOCK) { Thread.sleep(1000); } }synchronized(OUTER_LOCK){ synchronized(LOCK) { LOCK.wait(); } }。在这种情况下,sleep()将同时按住两个锁,但仍将wait()释放LOCKOUTER_LOCK
danze 17-10-19

243

我发现这篇文章很有帮助。它把之间的差异Thread.sleep()Thread.yield()以及Object.wait()对人类而言。报价:

最终,这一切都将归结到OS的调度程序,后者将时间片交给进程和线程。

sleep(n)说:“我已经完成了时间片,请在至少n毫秒内不要再给我另一个时间片。” 在请求的时间过去之前,操作系统甚至不会尝试调度休眠线程。

yield()说:“我已经完成了时间片,但还有很多工作要做。” 操作系统可以自由地立即给线程另一个时间片,或者给其他线程或处理CPU放弃的收益线程。

wait()说:“我已经完成了时间片。在有人致电notify()之前,不要给我另一个时间片。” 与一样sleep(),除非有人打电话notify()(或发生其他一些唤醒情况之一),否则操作系统甚至不会尝试安排任务。

当线程执行阻塞IO以及其他一些情况时,线程也会丢失其时间片的其余部分。如果线程在整个时间片中都正常工作,则操作系统将大致强制执行控制,就像yield()被调用一样,以便其他进程可以运行。

您很少需要yield(),但是如果您有一个具有逻辑任务边界的繁重应用程序,则插入yield() 可能会改善系统响应能力(以时间为代价-上下文切换,甚至只是向OS和向后切换都是免费的)。一如既往地根据您关心的目标进行衡量和测试。


收益率基本上取决于平台... javamex.com/tutorials/threads/yield.shtml
Pacerier 2014年

的解释sleep(n)隐式地说,当前正在运行的线程自动放弃了锁的监视器,这是不正确的。引用Thread的javadoc:“该线程不会失去任何监视器的所有权。”
克林特·伊斯特伍德

2
@Jonathan答案中没有提到监视器,这是因为sleep与监视器相比,它没有任何其他与Java方法调用有关的特殊行为,也就是说,它不以任何方式进行交互或修改。如果要对监视器说些什么,则应指定wait除上述内容外,还应暂时放弃对其调用的对象的锁定。
pqnet 2015年

通知在OS调度程序级别如何工作?通知是否使用特定的线程ID调用某种事件处理程序,从而允许调度程序将相关线程放回正在运行的队列中?另外我还有一个问题,自旋锁的概念适合什么地方?它仅与睡眠有关,还是等待自身使用极低的自旋锁?
CMCDragonkai 2015年

@Erich,用于wait(n)与进行比较sleep(n)。比较使用no-arg没有意义。
Pacerier

68

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

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

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

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

综上所述,通常sleep()用于时间同步和wait()多线程同步。

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


54

在这里,我列出了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()可以从任何地方调用。没有具体要求。

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

调用等待和睡眠方法的代码片段

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

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

线程转换为不同的线程状态


可以通过调用notify()唤醒睡眠线程是否正确?这里的其他一些帖子似乎暗示睡眠线程不能被唤醒而是被打断。
berimbolo

是的,Thread.sleep()用于使处理器时间可用于其他线程。睡眠期可以通过中断(即JVM)来终止。阅读本stackoverflow.com/questions/4264355/...
roottraveller

那篇文章还说,interrupt()是什么唤醒睡眠线程?我指的是您发布的线程状态图,其中说notify或notifyAll使正在休眠(不等待)的线程恢复为可以运行。我只是想确保我理解这一点。
berimbolo

@berimbolo notify()notifyAll()Object类方法。因此,它们是所有类的obj可用的(即这里也有Thread类)。参见代码grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/…–
roottraveller

2
好的,我需要阅读更多有关线程调度的信息,因为我无法找到notify()或notifyAll()唤醒睡眠线程的实例,而只有interrupt()这样做。所有示例都将notify()和notifyAll()与等待某个监视器对象的线程相关。
berimbolo

29

在等待和睡眠之后,我总结出一些不同的主要说明,首先使用wait()和sleep()来研究示例:

Example1:使用wait()和sleep():

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对象的线程上调用
    • sleep():调用线程执行任务获取啤酒(是类方法,因此会影响当前运行的线程)
  2. 已同步
    • wait():当同步多线程访问同一对象(HandObject)时(当需要在同一对象HandObject上的多个线程(线程执行编码,线程执行获取啤酒)访问之间进行通信时)
    • sleep():等待条件继续执行时(可使用等待啤酒)
  3. 保持锁
    • wait():释放其他对象有机会执行的锁定(HandObject是免费的,您可以执行其他工作)
    • sleep():保持锁定至少t次(或直到中断)(我的工作仍未完成,我继续保持锁定并等待某种条件继续)
  4. 唤醒条件
    • wait():直到从对象调用notify(),notifyAll()
    • sleep():直到至少时间到期或调用中断
  5. 最后一点是使用,estani所示:

您通常使用sleep()进行时间同步,并使用wait()进行多线程同步。

如果我错了,请纠正我。


25

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

  • 最根本的区别是,wait()Objectsleep()是一个静态方法Thread

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

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

  • wait()应该从同步内部调用,否则我们会得到IllegalMonitorStateException,而sleep() 可以在任何地方调用。

  • 要再次从中启动线程wait(),您必须调用notify()notifyAll()。至于sleep(),线程是在指定的时间间隔后启动的。

相似之处

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

18

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

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

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

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

但是,在sleep()这种情况下,该方法可用于将过程保留几秒钟或所需的时间。因为您不需要激发任何notify()notifyAll()方法来返回该线程。或者,您不需要任何其他线程来回调该线程。就像您希望几秒钟后发生某些事情(例如在用户回合之后的游戏中)一样,您希望用户等到计算机播放后再提及该sleep()方法。

访谈中经常问sleep()到的另一个重要区别是:属于Thread阶级和wait()属于Object阶级。

这些都是sleep()和之间的区别wait()

两种方法之间有一个相似之处:它们都是被检查的语句,因此您需要尝试catch或throws来访问这些方法。

我希望这能帮到您。


16

来源: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(),只有活动线程不需要指向休眠线程的直接指针,而只需指向共享锁对象的指针。


14

等待和睡眠是两件事:

  • sleep()线程中停止工作指定的持续时间。
  • wait()线程停止工作之前,通常由其他线程通知正在等待的对象。

但是您可以中断正在休眠的线程。在这种情况下,wait()实际上是多余的,它也浪费了CPU周期:-(
Geek

9
等待不会浪费CPU周期。
PeterŠtibraný09年

1
@Peter-我认为是的。它等待()它的CPU周期块,然后OS将CPU周期分配给其他线程。我不确定这可能取决于操作系统。
极客

3
如果浪费CPU周期,wait()的实现将非常糟糕。等待/通知在线程间通信中被大量使用。
PeterŠtibraný09年

2
@Pacerier这两个构造用于不同的目的。如果您希望线程在固定的时间sleep内停止运行,如果希望它停止直到某个输入来自其他线程,则可以使用wait/ notifyinterrupt旨在作为一种信号通知线程它应该停止执行正在执行的操作并终止。它由处理sleepwait但也阻止了I / O函数(您可以通过调用method来实现具有相同行为的函数Thread.interrupted())。至于性能,通常会针对其设计目标对功能进行优化。
pqnet

11

sleep是的一种方法Threadwait是的一种方法Objectwait/notify也是一种在Java中同步共享数据的技术(使用monitor),但是它sleep是线程暂停自身的一种简单方法。


8

sleep()是一种用于将进程保留几秒钟或所需时间的方法,但是如果使用wait()方法,线程将进入等待状态,直到我们调用notify()或notifyAll()。

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

Thread.sleep()在一段时间内将当前线程发送到“不可运行”状态。该线程保留已获取的监视器,即,如果该线程当前处于同步块或方法中,则没有其他线程可以进入该块或方法。如果另一个线程调用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:

  • wait():调用一个对象;当前线程必须在锁对象上同步。
  • sleep():在线程上调用;始终当前正在执行的线程。

Synchronized:

  • wait():当多个线程同步访问一个对象时。
  • sleep():当多个线程同步时,等待睡眠线程的睡眠。

Hold lock:

  • wait():释放该锁,使其他对象有机会执行。
  • sleep():如果指定了超时或有人中断,则保持锁定至少t次。

Wake-up condition:

  • wait():直到从对象调用notify(),notifyAll()
  • sleep():直到至少时间到期或调用interrupt()。

Usage:

  • sleep():用于时间同步;
  • wait():用于多线程同步。

参考:diff sleepwait


6

简单来说,wait是等待,直到其他线程调用您,而sleep是在指定的时间段内“不执行下一条语句”。

此外,sleep是Thread类中的静态方法,它在线程上运行,而wait()在Object类中,并且在对象上调用。

还有一点,当您在某个对象上调用wait时,所涉及的线程将同步该对象,然后进行等待。:)


1
为什么同时需要两者?为什么sleep()不够?
极客

2
通知用于线程之间的通信。要调用等待,您需要一些对象,对其进行同步,然后在其上调用等待。要得到通知,您需要其他线程在同一对象上进行同步,然后调用notify。
PeterŠtibraný09年

6

waitsleep方法非常不同:

  • sleep 无法“唤醒”,
  • wait在等待期间可以通过另一个线程调用notify或来“唤醒” notifyAll

仔细想想,名字在这方面令人困惑;但是sleep是标准名称,wait类似于Win API中的WaitForSingleObjectWaitForMultipleObjects


3
但是我们可以打a 吗?那么,睡眠/中断与等待/通知有什么区别?
Pacerier

2
您可以打扰一个正在睡觉的人,但是您只能通知一个正在等待的人。线程是相同的。
Rishi

5

从这篇文章中:http : //javaconceptoftheday.com/difference-between-wait-and-sleep-methods-in-java/

wait()方法。

1)调用wait()方法的线程释放其持有的锁。

2)在其他线程在同一锁上调用notify()或notifyAll()方法之后,该线程重新获得该锁。

3)必须在同步块内调用wait()方法。

4)wait()方法总是在对象上调用。

5)等待线程可以被其他线程通过调用notify()或notifyAll()方法唤醒。

6)要调用wait()方法,线程必须具有对象锁定。

sleep()方法

1)调用sleep()方法的线程不会释放其持有的锁。

2)sleep()方法可以在同步块内部或外部调用。

3)sleep()方法总是在线程上调用。

4)其他线程无法唤醒睡眠线程。如果这样做,线程将抛出InterruptedException。

5)要调用sleep()方法,线程不需要具有对象锁定。


4
  1. wait()是一种Object上课的方法。
    sleep()是一种Thread上课的方法。

  2. sleep()允许线程进入sleep状态达x毫秒。
    当线程进入睡眠状态时it doesn’t release the lock

  3. wait()允许线程释放锁和goes to suspended state
    当为同一对象调用notify()or notifAll()方法时,该线程将处于活动状态。


4

睡眠/中断和等待/通知之间的一个潜在的大区别是

在不需要时生成异常的效率很低。如果您的线程彼此之间的通信速度很高,那么如果您一直在调用中断,则会产生很多异常,这是对CPU的完全浪费。


+1,实际上是一个有效的观点,尽管争论实现的内部可能与性能分析更相关...
Pacerier 2014年

换句话说,创建异常的开销可能大大小于系统实现一个与另一个实现的开销。
Pacerier

3

您是正确的-Sleep()导致该线程“休眠”,并且CPU将会关闭并处理其他线程(否则称为上下文切换),我相信Wait会保持CPU处理当前线程。

两者兼有是因为虽然让您在不使用CPU时让其他人使用CPU似乎很明智,但实际上上下文切换会产生开销-根据睡眠时间长短,CPU周期可能会更昂贵切换线程要比简单地让您的线程在几毫秒内什么都不做更重要。

另请注意,睡眠会强制进行上下文切换。

另外-通常无法控制上下文切换-在“等待”期间,操作系统可能(并且将等待更长的时间)选择处理其他线程。


4
wait()不会让CPU处理当前线程。就像睡眠一样,它也会引起上下文切换:javamex.com/tutorials/threads/context_switch.shtml。我一直在围绕stackoverflow询问半年,似乎没人知道等待/通知与睡眠/中断之间有什么区别。
Pacerier

尽管睡眠并不能使CPU继续处理当前线程,但我认为这对CPU来说还是有点负担,因为CPU需要跟踪何时结束睡眠。它没有等待中的外部触发器,例如“ notify”。没有?
弗拉基米尔·纳博科夫(Fladimir Nabokov),

@VladimirNabokov,外部触发器为interrupt。结束时间是nwait(n)。¶¶已经八年了,仍然没有人能回答!
Pacerier

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)因此可以使用waitto er,sleep但是随后您就不得不打扰锁了。

在睡眠/等待时,这两种方法均未使用cpu。

这些方法是使用本机代码,使用类似的构造但不是以相同的方式实现的。

自己找:本机方法的源代码可用吗?该文件/src/share/vm/prims/jvm.cpp是起点...


Thread.sleep计时也可以设置为不确定。也可以将Object.wait计时设置为确定的。这个答案不能解释为什么我们需要两把锤子做同样的事情。
Pacerier 2014年

Thread.sleep(big_num) 必须被打断。Object.wait(small_num) 可以通知。
Pacerier


3

Wait()和sleep()的区别?

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()进入等待阶段时,将释放该键,并等待基于参数的几秒钟。

例如:

您用右手拿咖啡,也可以用同一只手拿另一个人,什么时候放下,然后只拿一个同类型的物体。也。这是sleep()你睡觉的时间你没有做任何工作,你只在睡觉。

等待()。当你放下心,在等待的时候再说一次,那就是等待

您正在播放电影或与您的播放器相同的系统中的任何内容,一次不能播放多个,这就是这里,当您关闭并选择另一首电影或歌曲时,这意味着等待


3

wait释放锁而sleep不会释放。处于等待状态的线程有资格在notify或被notifyAll调用时唤醒。但是在sleep线程保持锁定的情况下,只有在睡眠时间结束后才有资格使用线程。


因此,如果线程正在睡眠10秒钟并且发生了中断的异常?
极客2014年

就像InterruptedExceptionJavadoc中所说的那样,将引发@Geek An 。
user207421 '16

@EJP:您和sun.java.com论坛中的EJP是同一个人吗?至少您的分数表示相同:-)
怪胎

2

sleep()方法导致当前线程在指定的时间内从运行状态移动到块状态。如果当前线程拥有任何对象的锁,那么它将继续持有它,这意味着其他线程无法在该类对象中执行任何同步方法。

wait() 方法使当前线程在指定时间或直到通知之前进入块状态,但是在这种情况下,该线程释放对象的锁定(这意味着其他线程可以执行调用对象的任何同步方法。


2

在我看来,这两种机制之间的主要区别在于,睡眠/中断是处理线程的最基本方法,而等待/通知是一种抽象,旨在简化线程之间的通信。这意味着睡眠/中断可以执行任何操作,但是此特定任务很难执行。

为什么等待/通知更合适?以下是一些个人注意事项:

  1. 它强制集中化。它允许协调具有单个共享库的一组线程之间的通信。这大大简化了工作。

  2. 它强制执行同步。因为这使程序员可以将调用包装在同步块中以等待/通知。

  3. 它与线程的来源和编号无关。使用这种方法,您可以任意添加更多线程,而无需编辑其他线程或跟踪现有线程。如果使用了睡眠/中断,则首先需要保留对睡眠线程的引用,然后手动逐个中断它们。

现实生活中的一个很好的例子可以解释这是一家经典餐厅以及员工之间进行交流的方法:服务员将客户的要求放在一个中央位置(软木板,桌子等),敲钟,厨房的工人来接了这样的要求。一旦准备好任何菜,厨房人员就会再次按铃,以使服务员意识到并把它们带给顾客。


2

关于睡眠的示例不会释放锁定,而等待会释放

这里有两个类:

  1. Main:包含main方法和两个线程。
  2. Singleton:这是具有两个静态方法getInstance()和getInstance(boolean isWait)的Singleton类。

    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实例是相同的。这意味着线程B正在外部等待,直到线程A释放它的锁为止。

现在,通过注释Thread.sleep(500)来更改Singleton.java;方法并取消注释Singleton.class.wait(500); 。这里是因为Singleton.class.wait(500); 方法threadA将释放所有获取锁,并进入“非可运行状态”,线程B将获得更改以进入同步块。

现在再次运行:

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

在这里,线程A和线程B创建的Singleton实例是不一样的,因为线程B更改为进入同步块,并且在500毫秒后,线程A从其最后一个位置开始,并创建了另一个Singleton对象。


2

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

IllegalMonitorStateException:如果wait()在未获取对象锁的情况下调用方法的情况与IllegalMonitorStateException在运行时sleep()引发的方法不同,但方法永远不会引发此类异常。

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

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

线程状态:wait()方法被调用的对象,跟帖说holded者对象的监视器从运行到待机状态去,并可以返回到可运行状态,只有当notify()notifyAll()方法被调用该对象上。之后,线程调度程序会调度该线程从可运行状态变为运行状态。sleep()在线程上调用when时,它将从运行状态变为等待状态,并且在睡眠时间到时可以返回到可运行状态。

从同步块调用wait():调用方法时,线程将对象锁定。但是sleep(),从同步块或方法线程中调用方法时,不会留下对象锁定。

更多参考


可能比那个参考网址更好。
Drew

2

从oracle文档页面上的wait()方法Object

public final void wait()
  1. 使当前线程等待,直到另一个线程调用该对象notify()notifyAll()方法。换句话说,此方法的行为就像完全执行call一样wait(0)
  2. 当前线程必须拥有该对象的监视器。线程释放此监视器的所有权,并等待直到另一个线程通知等待在此对象的监视器上唤醒的线程
  3. 可能会产生中断和虚假唤醒
  4. 此方法只能由作为该对象的监视器的所有者的线程调用

该方法抛出

  1. IllegalMonitorStateException -如果当前线程不是对象监视器的所有者。

  2. InterruptedException-如果有任何线程在当前线程等待通知之前或期间中断了当前线程。引发此异常时,将清除当前线程的中断状态。

从oracle文档页面上关于类的sleep()方法的信息Thread

public static void sleep(long millis)
  1. 根据系统计时器和调度程序的精度和准确性,使当前正在执行的线程进入休眠状态(暂时停止执行)达指定的毫秒数。
  2. 该线程不会失去任何监视器的所有权。

该方法抛出:

  1. IllegalArgumentException -如果Millis值为负

  2. InterruptedException-如果有任何线程中断了当前线程。引发此异常时,将清除当前线程的中断状态。

其他关键区别:

wait()与静态方法sleep()(类方法)不同,它是一种非静态方法(实例方法)。



1
  • 该方法wait(1000)使当前线程休眠一秒钟
    • 如果线程接收到notify()notifyAll()方法调用,则其睡眠时间可能少于1秒。
  • 调用将sleep(1000)导致当前线程休眠1秒
    • 另外,睡眠线程不持有锁定任何资源。但是等待线程可以。

1
sleep(1000)不能保证准确地睡1秒钟。它可能之前被打断过。
2014年

1
这些帖子太混乱了。该线程上的所有其他帖子都说,休眠线程确实持有该锁,而等待线程确实持有该锁。类似地,带有该图的帖子暗示对notify()的调用唤醒睡眠线程,而其他帖子(和线程状态图)则意味着只有interrupt()或经过的超时时间才能执行此操作。我只是在实践中为自己订购了Java并发副本,这是我很久以前应该阅读的内容!
berimbolo

1

实际上,所有这些在Java文档中都有清楚的描述(但是我只有在阅读了答案之后才意识到这一点)。

http://docs.oracle.com/javase/8/docs/api/index.html

wait()-当前线程必须拥有此对象的监视器。线程释放此监视器的所有权,并等待直到另一个线程通过调用notify方法或notifyAll方法通知等待在此对象监视器上等待的线程唤醒。然后,线程等待,直到它可以重新获得监视器的所有权并恢复执行。

sleep()-根据系统计时器和调度程序的精度和准确性,使当前正在执行的线程进入休眠状态(暂时停止执行)达指定的毫秒数。该线程不会失去任何监视器的所有权。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.