Java中的“等待()”与“睡眠()”之间的区别

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

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

为什么我们有两者wait()sleep()

它们的实施在较低级别如何变化?

970503 次浏览

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

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

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

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

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

如果有多个线程在监视器上等待,您也可以调用#0-这将唤醒把他们都举起来。然而,只有一个线程能够抓住监视器(记住waitsynchronized块中)并继续-其他人将被阻塞,直到他们能够获得监视器的锁。

另一点是,您在#1本身调用wait(即您在对象的监视器上等待),而您在#3调用sleep

还有一点是,您可以从wait中获得虚假唤醒(即等待的线程无缘无故地恢复)。您应该在某些条件下旋转时总是#0如下:

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

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

此外,睡眠是Thread类中的静态方法,它对线程进行操作,而等待()是在Object类中并对对象进行调用。

另一点,当你在某个对象上调用等待时,所涉及的线程会同步该对象,然后等待。:)

waitsleep方法非常不同:

  • #0没有办法“唤醒”,
  • #0在等待期间有一种“唤醒”的方式,由另一个线程调用#1#2

仔细想想,这些名称在这方面令人困惑;然而sleep是一个标准名称,wait就像Win API中的#2#3

等待和睡觉是两回事:

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

你是对的——睡眠()导致该线程“睡眠”,CPU将关闭并处理其他线程(也称为上下文切换),而我相信等待会让CPU处理当前线程。

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

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

此外-通常不可能控制上下文切换-在等待期间,操作系统可能(并且会等待更长时间)选择处理其他线程。

一个尚未提及的关键区别是:

  • sleep()释放线程上的锁,

    synchronized(LOCK) {Thread.sleep(1000); // LOCK is held}
  • wait()发布它对对象持有的锁。

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

我发现这篇文章很有帮助。它把Thread.sleep()Thread.yield()Object.wait()之间的区别放在了人类的角度。引用:

这一切最终都会进入操作系统的调度程序,其中向进程和线程分发时间片。

sleep(n)表示我的时间片用完了,请不要给我另一个至少n毫秒。“操作系统甚至没有尝试调度休眠线程,直到请求的时间过去。

yield()表示"我的时间片用完了,但我还有工作要做"操作系统可以自由地立即给线程另一个时间片,或者给一些其他线程或进程CPU产生线程我放弃了

wait()表示"我的时间片用完了。别再给我了sleep()一样,操作系统不会甚至尝试安排您的任务,除非有人调用notify()(或其中之一)其他一些唤醒场景发生)。

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

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

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

#0将当前线程发送到“不可运行”状态一段时间。线程保留它已获取的监视器--即如果线程当前处于同步块或方法中,则没有其他线程可以进入此块或方法。如果另一个线程调用#0,它将唤醒休眠线程。

注意睡眠是一个静态方法,这意味着它总是影响当前线程(正在执行睡眠方法的线程)。A常见的错误是调用t.sleep(),其中t是不同的线程;即使这样,也是当前线程休眠,而不是t线程。

#0已弃用。使用它可以停止其他线程一个挂起的线程保持它所有的监视器和因为这种状态是不可中断的,所以很容易死锁。

#0将当前线程发送到“不可运行”状态,类似于sleep(),但有一个转折。等待是在对象上调用的,而不是线程;我们称这个对象为“锁对象”调用,当前线程必须在锁对象上同步;wait()然后释放此锁,并将线程添加到“等待列表”中与锁关联。稍后,另一个线程可以在相同的锁对象并调用lock.notify()。这会唤醒原始的,等待线程。基本上,wait()/notify()就像sleep()/interrupt(),只有活动线程不需要直接指向休眠线程的指针,但仅指向共享锁对象。

假设你正在听歌曲。

只要当前歌曲正在运行,下一首歌曲就不会播放,即下一首歌曲调用的Sep()

如果你完成了这首歌,它将停止,直到你选择播放按钮(通知()),它不会播放,即等待()调用当前的歌曲。

在这两种情况下,歌曲都会进入等待状态。

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

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

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

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

但是在sleep()的情况下,这是一个用于保持进程几秒钟或你想要的时间的方法。因为你不需要激发任何notify()notifyAll()方法来恢复该线程。或者你不需要任何其他线程来回调该线程。就像如果你希望几秒钟后发生什么,比如在轮到用户后的游戏中,你希望用户等到计算机播放,那么你可以提到sleep()方法。

还有一个在面试中经常被问到的更重要的区别:sleep()属于Thread类,wait()属于Object类。

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

这两种方法之间有相似之处:它们都是检查语句,因此您需要尝试捕获或抛出来访问这些方法。

我希望这将帮助你。

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

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

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

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

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

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

在处理了等待和睡眠之后,我总结出了一些不同的关键注意事项,首先看看使用等待()和睡眠()的示例:

实例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. 呼唤
    • 等待():调用当前持有HandObject对象的线程
    • 睡眠():调用线程执行任务获取啤酒(是类方法所以影响当前正在运行的线程)
  2. 同步
    • 等待():当同步的多线程访问同一个对象(HandObject)时(当需要多个线程之间通信(线程执行编码,线程执行获取啤酒)访问同一个对象HandObject时)
    • 睡眠():等待条件继续执行时(等待啤酒可用)
  3. 保持锁定
    • 等待():释放锁,让其他对象有机会执行(HandObject是免费的,你可以做其他工作)
    • 睡眠():保持锁至少t次(或直到中断)(我的工作还没有完成,我继续保持锁并等待一些条件继续)
  4. 唤醒条件
    • 等待():直到调用通知(),通知所有()从对象
    • 睡眠():直到至少时间到期或调用中断
  5. 最后一点是使用时,因为estani表示:

您通常使用睡眠()进行时间同步,并使用等待()进行时间同步多线程同步。

如果我错了,请纠正我。

sleepThread的方法,waitObject的方法,因此wait/notify是在Java中同步共享数据的技术(使用监视器),但sleep是线程暂停自身的简单方法。

wait()在同步方法中给出而sleep()是在非同步方法中给出的,因为wait()方法释放了对象上的锁,但sleep()yield()确实释放了lock()

这些方法用于不同的事情。

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。

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

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

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

在不需要的时候生成异常是低效的。如果你的线程以很高的速率相互通信,那么如果你一直调用中断,它会生成很多异常,这完全是浪费CPU。

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

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

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

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

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

睡眠()-使当前执行的线程在指定的毫秒数内休眠(暂时停止执行),具体取决于系统计时器和调度程序的精度和准确性。线程不会失去任何监视器的所有权。

这里等待()将处于等待状态,直到它被另一个线程通知,但作为睡眠()将有一段时间…之后,它将自动转移到就绪状态…

睡眠是一个方法,用于将进程保持几秒钟或您想要的时间,但在等待()方法的情况下,线程会处于等待状态,并且在我们调用通知()或通知()之前不会自动返回。

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

Thread.sleep()将当前线程发送到“不可运行”状态一段时间。线程保留它获取的监视器-即如果线程当前处于同步块或方法中,则没有其他线程可以进入该块或方法。如果另一个线程调用t.interrupt(),它将唤醒沉睡的线程。请注意,睡眠是一个静态方法,这意味着它总是影响当前线程(正在执行睡眠方法的线程)。一个常见的错误是调用t.sleep(),其中t是一个不同的线程;即便如此,将睡眠的是当前线程,而不是t线程。

object.wait()将当前线程发送到“不可运行”状态,就像睡眠()一样,但有一个扭曲。等待是在一个对象上调用的,而不是一个线程;我们称这个对象为“锁对象”。在调用lock.wait()之前,当前线程必须在锁对象上同步;等待()然后释放这个锁,并将线程添加到与锁关联的“等待列表”中。稍后,另一个线程可以在同一个锁对象上同步并调用lock.notify()。这唤醒了原来的等待线程。基本上,等待()/通知()就像睡眠()/中断()一样,只有活动线程不需要指向睡眠线程的直接指针,而只需要指向共享锁对象。

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

让我们对以上所有要点进行分类:

Call on:

  • 等待():调用对象;当前线程必须在锁对象上同步。
  • 睡眠():调用线程;总是当前正在执行的线程。

Synchronized:

  • 等待():当同步多个线程一个接一个地访问同一个Object时。
  • 睡眠():当同步的多个线程等待睡眠线程的睡眠结束时。

Hold lock:

  • 等待():释放锁,让其他对象有机会执行。
  • 睡眠():如果指定超时或有人中断,则保持锁定至少t次。

Wake-up condition:

  • 等待():直到从对象调用通知()、通知所有()
  • 睡眠():直到至少时间到期或调用中断()。

Usage:

  • 睡眠():用于时间同步和;
  • 等待():用于多线程同步。

参考:diff#0和#1

在我看来,这两种机制之间的主要区别在于睡眠/中断是处理线程的最基本方式,而等待/通知是一个抽象,旨在使线程间通信更容易。这意味着睡眠/中断可以做任何事情,但这个特定的任务更难做。

为什么等待/通知更合适?以下是一些个人考虑因素:

  1. 它允许使用单个共享对象协调一组线程之间的通信。这大大简化了工作。

  2. 因为它使程序员将等待/通知的调用包装在一个同步块中。

  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当它进入等待阶段时,它将释放密钥并根据参数等待一些秒。

例如:

你右手拿着咖啡,你可以拿同一只手的任何人,你什么时候放下然后只拿另一个相同类型的对象。还有。这是睡眠()你睡觉的时候你没有任何工作,你只是在睡觉…这里也一样。

等待()。当你被放下并在等待时再拿一个时,那就是等待

你是播放电影或任何东西在你的系统一样的球员你不能玩一个以上的时间对,这就是它在这里,当你关闭并选择另一个任何人电影或歌曲的意思是当被称为等待

  1. wait()Object类的方法。
    sleep()Thread类的方法。

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

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

wait()具有超时值,可以在超时值过去时唤醒或通知(或中断),然而,sleep()在超时值经过或中断(以较早者为准)时唤醒。没有超时值的wait()将永远等待,直到通知或中断。

wait释放锁,sleep不释放。处于等待状态的线程有资格在notifynotifyAll被调用时立即唤醒。但是在sleep的情况下,线程保留锁,只有在睡眠时间结束后才有资格。

关于睡眠不释放锁和等待的示例

这里有两个类:

  1. 主要:包含main方法和两个线程。
  2. Singleton:这是一个单例类,有两个静态方法getInstance()和getInstance(boolean is等待)。

    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() {@Overridepublic void run() {
    singletonA = Singleton.getInstance(true);
    }};
    Thread threadB = new Thread() {@Overridepublic 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();
    }}

and

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 waitThread.sleep(500);// Using SleepSystem.out.println("_instance :"+ String.valueOf(_instance));} catch (InterruptedException e) {e.printStackTrace();}}
_instance = new Singleton();}}}return _instance;
}}

现在运行这个例子,你将得到以下输出:

_instance :nullBoth singleton are same

这里threadA和threadB创建的Singleton实例是相同的。这意味着threadB在外面等待,直到threadA释放它的锁。

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

现在再次运行:

SingletonA still nullSingletonA still nullSingletonA still null_instance :com.omt.sleepwait.Singleton@10c042abSingletonA still nullSingletonA still nullSingletonA still nullBoth singleton are not same

这里threadA和threadB创建的Singleton实例不一样,因为threadB在同步块中输入了更改,并且在500毫秒后threadA从它的最后一个位置开始并创建了一个Singleton对象。

本文链接:http://javaconceptoftheday.com/difference-between-wait-and-sleep-methods-in-java/

etc()方法。

1)调用等待()方法的线程释放它持有的锁。

2)在其他线程调用同一锁上的通知()或通知()方法后,线程重新获得锁。

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

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

5)等待线程可以被其他线程唤醒,方法是调用通知()或通知()。

6)要调用等待()方法,线程必须有对象锁。

睡眠方法

1)调用睡眠()方法的线程不会释放它持有的锁。

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

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

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

5)要调用睡眠()方法,线程不需要对象锁。

等待()和睡眠()的区别

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

相似之处

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

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

非法监控器状态异常:如果调用wait()方法而没有获取对象锁,则在运行时抛出IllegalMonitorStateException,但sleep()方法永远不会抛出此类异常。

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

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

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

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

更多参考

在这里,我列出了wait()sleep()方法之间的一些重要区别。
PS:还可以点击链接查看库代码(内部工作,只是为了更好地理解而玩一下)。

等待()

  1. wait()方法释放锁。
  2. wait()Object类的方法。
  3. wait()是非静态方法-公共最终无效等待()抛出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}

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

从Oracle留档页等待()方法Object

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

这种方法抛出

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

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

从oracle留档页上的Thread class的睡眠方法:

public static void sleep(long millis)
  1. 使当前执行的线程在指定的毫秒数内休眠(暂时停止执行),具体取决于系统计时器和调度程序的精度和准确性。
  2. 线程不会丢失任何监视器的所有权。

此方法抛出:

  1. IllegalArgumentException-如果milis的值为负

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

其他关键区别:

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

等待()必须与同步包围,当线程进入同步块或方法时,它意味着获得锁,所以它不阻塞,调用等待意味着释放锁,所以它退出同步然后块,Thread.sleep()导致当前线程暂停执行一段指定的时间。