线程中的wait()和sleep()有什么区别?
我是否理解wait()-ing线程仍然处于运行模式并使用CPU周期,但sleep()-ing不消耗任何CPU周期正确?
为什么我们同时使用wait()和sleep()?
它们的实现在较低级别上有什么不同?
线程中的wait()和sleep()有什么区别?
我是否理解wait()-ing线程仍然处于运行模式并使用CPU周期,但sleep()-ing不消耗任何CPU周期正确?
为什么我们同时使用wait()和sleep()?
它们的实现在较低级别上有什么不同?
当前回答
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():用于多线程同步。
参考:差别睡眠和等待
其他回答
这些方法用于不同的事情。
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,呃,睡眠,但这样你就不得不使用锁了。
这两种方法都不会在休眠/等待时使用cpu。
这些方法是使用本地代码实现的,使用类似的结构,但方式不同。
自己寻找:本机方法的源代码是否可用?文件/src/share/vm/prims/jvm.cpp是起点…
一个等待线程可以被另一个调用正在被等待的监视器上的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()不会释放它在线程上持有的锁, 同步(锁){ thread . sleep (1000);// LOCK被持有 } Wait()释放它在对象上持有的锁。 同步(锁){ LOCK.wait ();// LOCK不被持有 }
Sleep()方法导致当前线程在指定的时间内从运行状态转移到阻塞状态。如果当前线程拥有任何对象的锁,那么它会一直持有它,这意味着其他线程不能在该类对象中执行任何同步方法。
Wait()方法会导致当前线程在指定的时间内进入阻塞状态或直到notify,但在这种情况下,线程会释放对象的锁(这意味着其他线程可以执行调用对象的任何同步方法)。