线程中的wait()和sleep()有什么区别?
我是否理解wait()-ing线程仍然处于运行模式并使用CPU周期,但sleep()-ing不消耗任何CPU周期正确?
为什么我们同时使用wait()和sleep()?
它们的实现在较低级别上有什么不同?
线程中的wait()和sleep()有什么区别?
我是否理解wait()-ing线程仍然处于运行模式并使用CPU周期,但sleep()-ing不消耗任何CPU周期正确?
为什么我们同时使用wait()和sleep()?
它们的实现在较低级别上有什么不同?
当前回答
你是正确的- Sleep()导致线程“睡眠”,CPU将离开并处理其他线程(也称为上下文切换),而我认为Wait保持CPU处理当前线程。
我们两者都有,因为尽管让其他人在你不使用CPU时使用它似乎是明智的,但实际上上下文切换是有开销的——取决于睡眠的时长,在CPU周期中切换线程可能比简单地让你的线程在几毫秒内什么都不做要昂贵得多。
还要注意,睡眠会强制进行上下文切换。
此外——通常情况下控制上下文切换是不可能的——在等待期间,操作系统可能(并且会有更长的等待)选择处理其他线程。
其他回答
让我们假设你正在听到歌曲。
只要当前歌曲正在运行,下一首歌就不会播放,即由下一首歌调用Sleep()
如果你完成了这首歌,它会停止,直到你选择播放按钮(notify())它才会播放,即由当前歌曲调用的wait()。
在这两种情况下,歌曲都进入等待状态。
一个等待线程可以被另一个调用正在被等待的监视器上的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(); }
}
在我看来,这两种机制之间的主要区别在于,睡眠/中断是处理线程的最基本方式,而等待/通知是一种抽象,旨在使线程间的通信更容易。这意味着睡眠/中断可以做任何事情,但这个特定的任务更难完成。
为什么等待/通知更合适?以下是一些个人考虑:
它加强了中央集权。它允许使用单个共享对象协调一组线程之间的通信。这大大简化了工作。 它强制同步。因为它使程序员将等待/通知调用包装在同步块中。 它与线程的起源和编号无关。使用这种方法,您可以任意添加更多线程,而无需编辑其他线程或跟踪现有线程。如果使用sleep/interrupt,首先需要保留对休眠线程的引用,然后手动逐个中断它们。
一个来自现实生活的例子很好地解释了这一点,一个经典的餐厅和员工之间用来沟通的方法:服务员把顾客的要求放在一个中心的地方(一块软木板,一张桌子等),摇铃,然后厨房的工人来接受这些要求。一旦有菜准备好了,厨房工作人员就会再次按铃,让服务员知道并把菜送到顾客面前。
sleep()是一个用来保持进程几秒钟或你想要的时间的方法,但如果wait()方法线程处于等待状态,它不会自动返回,直到我们调用notify()或notifyAll()。
主要的区别是wait()释放锁或监视器,而sleep()在等待时不释放任何锁或监视器。Wait用于线程间通信,而sleep通常用于在执行时引入暂停。
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
}
让我们对以上几点进行分类:
呼吁:
wait():调用一个对象;当前线程必须同步锁对象。 sleep():在线程上调用;总是当前执行线程。
同步:
wait():同步的多个线程逐个访问同一个对象。 Sleep():当同步的多个线程等待休眠线程的休眠。
持有锁:
Wait():释放锁,让其他对象有机会执行。 Sleep():如果指定超时或有人中断,则保持锁定至少t次。
唤醒条件:
wait():直到调用notify(), notifyAll()从对象 Sleep():直到至少超时或调用interrupt()。
用法:
Sleep():用于时间同步和; Wait():用于多线程同步。
参考:差别睡眠和等待
来源: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(),只有活动线程不需要直接 指向睡眠线程的指针,但仅指向共享锁对象。