wait和sleep的区别,这真是在面试中一个高高高高频的面试题。
哈哈,要想说完这两个家伙的所有区别还是不太容易的,今天我们就来总结下这两个方法的区别。
把小本本拿出来,一条条记下来。
我们先来看看源码,是不是一听要看源码就脑阔疼,放心,这两个方法源码还是容易理解的。因为它们两个是native
方法😂。
/**
* Causes the current thread to wait until either another thread invokes the
* {@link java.lang.Object#notify()} method or the
* {@link java.lang.Object#notifyAll()} method for this object, or a
* specified amount of time has elapsed.
* <p>
* The current thread must own this object's monitor.
* <p>
* This method causes the current thread (call it <var>T</var>) to
* place itself in the wait set for this object and then to relinquish
* any and all synchronization claims on this object. Thread <var>T</var>
* becomes disabled for thread scheduling purposes and lies dormant
* until one of four things happens:
* <ul>
* <li>Some other thread invokes the {@code notify} method for this
* object and thread <var>T</var> happens to be arbitrarily chosen as
* the thread to be awakened.
* <li>Some other thread invokes the {@code notifyAll} method for this
* object.
* <li>Some other thread {@linkplain Thread#interrupt() interrupts}
* thread <var>T</var>.
* <li>The specified amount of real time has elapsed, more or less. If
* {@code timeout} is zero, however, then real time is not taken into
* consideration and the thread simply waits until notified.
* </ul>
* The thread <var>T</var> is then removed from the wait set for this
* object and re-enabled for thread scheduling. It then competes in the
* usual manner with other threads for the right to synchronize on the
* object; once it has gained control of the object, all its
* synchronization claims on the object are restored to the status quo
* ante - that is, to the situation as of the time that the {@code wait}
* method was invoked. Thread <var>T</var> then returns from the
* invocation of the {@code wait} method. Thus, on return from the
* {@code wait} method, the synchronization state of the object and of
* thread {@code T} is exactly as it was when the {@code wait} method
* was invoked.
* <p>
* A thread can also wake up without being notified, interrupted, or
* timing out, a so-called <i>spurious wakeup</i>. While this will rarely
* occur in practice, applications must guard against it by testing for
* the condition that should have caused the thread to be awakened, and
* continuing to wait if the condition is not satisfied. In other words,
* waits should always occur in loops, like this one:
* <pre>
* synchronized (obj) {
* while (<condition does not hold>)
* obj.wait(timeout);
* ... // Perform action appropriate to condition
* }
* </pre>
* (For more information on this topic, see Section 3.2.3 in Doug Lea's
* "Concurrent Programming in Java (Second Edition)" (Addison-Wesley,
* 2000), or Item 50 in Joshua Bloch's "Effective Java Programming
* Language Guide" (Addison-Wesley, 2001).
*
* <p>If the current thread is {@linkplain java.lang.Thread#interrupt()
* interrupted} by any thread before or while it is waiting, then an
* {@code InterruptedException} is thrown. This exception is not
* thrown until the lock status of this object has been restored as
* described above.
*
* <p>
* Note that the {@code wait} method, as it places the current thread
* into the wait set for this object, unlocks only this object; any
* other objects on which the current thread may be synchronized remain
* locked while the thread waits.
* <p>
* This method should only be called by a thread that is the owner
* of this object's monitor. See the {@code notify} method for a
* description of the ways in which a thread can become the owner of
* a monitor.
*
* @param timeout the maximum time to wait in milliseconds.
* @throws IllegalArgumentException if the value of timeout is
* negative.
* @throws IllegalMonitorStateException if the current thread is not
* the owner of the object's monitor.
* @throws InterruptedException if any thread interrupted the
* current thread before or while the current thread
* was waiting for a notification. The <i>interrupted
* status</i> of the current thread is cleared when
* this exception is thrown.
* @see java.lang.Object#notify()
* @see java.lang.Object#notifyAll()
*/
public final native void wait(long timeout) throws InterruptedException;
public final void wait() throws InterruptedException {
wait(0);
}
public final void wait(long timeout, int nanos) throws InterruptedException {
if (timeout < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
if (nanos > 0) {
timeout++;
}
wait(timeout);
}
/**
* Causes the currently executing thread to sleep (temporarily cease
* execution) for the specified number of milliseconds, subject to
* the precision and accuracy of system timers and schedulers. The thread
* does not lose ownership of any monitors.
*
* @param millis
* the length of time to sleep in milliseconds
*
* @throws IllegalArgumentException
* if the value of {@code millis} is negative
*
* @throws InterruptedException
* if any thread has interrupted the current thread. The
* <i>interrupted status</i> of the current thread is
* cleared when this exception is thrown.
*/
public static native void sleep(long millis) throws InterruptedException;
public static void sleep(long millis, int nanos)
throws InterruptedException {
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
millis++;
}
sleep(millis);
}
你肯定在想,源码这么简单为什么要把注释也展示出来。
因为是native方法,我们只能靠看注释了解它们的一些信息了。
我们先来看看sleep方法的注释
* Causes the currently executing thread to sleep (temporarily cease
* execution) for the specified number of milliseconds, subject to
* the precision and accuracy of system timers and schedulers. The thread
* does not lose ownership of any monitors.
还是比较简单的,主要说了该方法会导致当前正在执行的线程休眠,是临时的暂停执行哦。
这个睡眠时间是我们必须要传的,休眠时间的精度受系统的定时器和调度器影响。
最后一点比较重要,不会放弃拥有的锁。
我们再来看看wait方法的注释
是不是觉得wait方法的注释好长呀,我第一次看的时候也觉得😅。
所以咱们就拆开来,一点一点啃掉这根硬骨头吧。(嗯?怎么说的物种都变了喃
* Causes the current thread to wait until either another thread invokes the
* {@link java.lang.Object#notify()} method or the
* {@link java.lang.Object#notifyAll()} method for this object, or a
* specified amount of time has elapsed.
首先前几行注释告诉我们,该方法会导致当前线程进入wait的状态。
然后只能被其它线程调用Object的notify()或notifyAll()方法唤醒,也可以指定了被唤醒的时间,这样也可以自动被唤醒。如果传的时间为0的话,就真的只能被其它线程唤醒了。(唉,命运就掌握在别的线程手里了
* The current thread must own this object's monitor.
* <p>
* This method causes the current thread (call it <var>T</var>) to
* place itself in the wait set for this object and then to relinquish
* any and all synchronization claims on this object.
敲黑板,重点来啦。
如果要调用wait方法是有条件的,当前线程必须要拥有该对象的监视器。
你可能会问,这是什么意思呀?
别着急,看下面的代码我们瞬间就懂了。
String lock = "a";
synchronized (lock) {
lock.wait();
}
其实就是,当前线程要拥有lock对象的锁时,才能调用lock对象的wait方法。顺便提一下,notify和notifyAll方法也需要先拥有对象的锁才能调用。
不然会抛出java.lang.IllegalMonitorStateException
异常。
好了,我们现在可以来总结下啦
区别1:sleep方法是属于java.lang.Thread
类;wait方法是属于java.lang.Object
类。
区别2:sleep方法是静态方法;wait方法不是静态方法,是一个final方法,不能被子类重写。
区别3:sleep方法不用获得锁就能执行;wait方法必须要获得对象的锁时,才能调用该对象的wait方法。
区别4:sleep方法必须要传参数,参数为0时,表示休眠0毫秒,所以会马上被唤醒;wait方法传的参数为0时,表示永久休眠,只能被其它线程调用notify和notifyAll方法唤醒。
区别5:sleep方法不会放弃获取到的锁;wait方法会放弃获取到的锁(其实也能想的明白,你不放弃,其它线程怎么获取到该对象的锁来唤醒当前线程哇)。
它们两个还是有共同点的
比如都会抛出编译时异常InterruptedException
,该异常会在调用那个线程的interrupt()方法时被抛出。
举个栗子🌰,现在我们有A和B两个线程,如果A线程执行了sleep或者wait方法进入休眠状态,此时B线程调用A线程对象.interrupt()
方法时,A线程就会抛出InterruptedException异常,相当于也被唤醒了。