今天,来聊一聊线程的 sleep() 方法和 wait() 方法的区别:
首先,先看源码:
可以看出,sleep() 方法是 Thread 类的方法,底层是直接调用的 C++文件去执行线程的 sleep();
而wait()方法则是 Object类的方法,而我们知道,Java中Object类是所有类的父类,也就意味着,所有的类都有 wait() 方法。wait()方法的底层也是调用的 C++ 文件的方法去执行。
共同点:sleep()方法与 wait()方法都可以让线程暂停一段时间:
public class OrderAppTest {
public static void main(String[] args) {
Test test = new Test();
System.out.println("mainThread beginTime:" + System.currentTimeMillis());
test.start();
}
}
class Test extends Thread {
@Override
public void run() {
try {
sleep(5000);
System.out.println("Runnable beginTime:" + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
sleep()方法停止线程的效果如下:
再来看 wait() 方法的效果:
public class OrderAppTest {
public static Object object = new Object();
public static void main(String[] args) {
synchronized (object){
System.out.println("mainThread beginTime:" + System.currentTimeMillis());
try {
object.wait(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("mainThread endTime:" + System.currentTimeMillis());
}
}
}
运行效果图如下:
从代码的运行效果上看,sleep() 方法和 wait() 方法都具备使线程暂停一段时间的效果。【可能有些初学者看不懂wait()的使用示例代码,稍后,我会介绍 synchronized 关键字和 wait() 方法的使用方法】
不同点:sleep() 方法暂停期间,不会释放锁,而 wait() 方法被执行后,会立即释放锁,关于锁的理解,请看这篇文章:【】
照例,通过一段测试代码来理解一下:
public class OrderAppTest {
public static void main(String[] args) {
Test test = new Test();
Thread a = new Thread(test, "A");
Thread b = new Thread(test, "B");
a.start();
b.start();
}
}
class Test extends Thread{
@Override
synchronized public void run() {
System.out.println(currentThread().getName() + "线程,BeginTime:" + System.currentTimeMillis());
try {
sleep(5000 );
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(currentThread().getName() + "线程,EndTime:" + System.currentTimeMillis());
}
}
运行该段代码,打印结果如下:
从运行结果可以看出,在A线程sleep()期间,B线程拿不到锁,无法进入run()方法;由此,得出结论:sleep()方法暂停期间,线程是不释放锁的。
下面我们来看 wait() 方法:
public class OrderAppTest {
public static void main(String[] args) {
Test test = new Test(new Object());
Thread a = new Thread(test, "A");
Thread b = new Thread(test, "B");
a.start();
b.start();
}
}
class Test extends Thread{
private Object object;
public Test(Object object) {
this.object = object;
}
@Override
public void run() {
synchronized (object){
System.out.println(currentThread().getName() + "线程,BeginTime:" + System.currentTimeMillis());
try {
object.wait(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(currentThread().getName() + "线程,EndTime:" + System.currentTimeMillis());
}
}
}
运行该段代码,打印结果如下:
从运行结果可以看出,A线程开始以后,执行到 object.wait(5000)处,A线程停止5秒,同时立即释放锁,这时,等待获取object对象锁的B线程获得锁,开始执行,同样执行到object.wait(5000)处,B线程停止5秒,同时,释放锁;A线程苏醒,获得锁,继续执行wait()之后的代码,执行完成,A线程释放锁;B线程苏醒后,A线程已经执行完成并释放锁,B线程重新获得锁,继续执行wait()之后的代码,执行完成,B线程释放锁,程序运行结束。故,得出结论:wait() 暂停期间,会释放锁,当暂停时间结束后,线程会重新去争夺锁,然后继续运行wait()方法之后的代码。
接下来,我们继续看一下wait()方法:wait()方法的JDK源码其实已经讲的很清楚了:
/**
* @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;
我们看,方法注解里抛出的第二个异常说明:翻译一下就是:
如果当前线程不是对象监视器的所有者(这里所说的对象监视器即:锁)。则会抛出 IllegalMonitorStateException 异常。也就是说,调用wait()方法,必须持有对象锁,否则会抛出异常。
而调用sleep()方法则不需要持有对象锁。
/**
* @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;
注意看wait()方法和sleep()方法的注解,两个方法抛出的异常中,sleep()方法不会抛出 IllegalMonitorStateException异常,也就是说,调用sleep()方法时,是否持有对象锁其实无所谓,都不会报错。
最后,总结一下:
wait() 与 sleep() 的相同点:
都可以使线程暂停一段时间。
不同点:
sleep()方法是 Thread 类的方法,wait()方法是 Object 类的方法。
调用sleep()不需要当前线程持有对象锁,而wait()方法则需要当前线程必须持有对象锁,否则抛出 IllegalMonitorStateException 异常。
如果调用sleep() 方法的线程持有锁的话,sleep()方法被调用后,该线程不会释放锁,会等待sleep()暂停时间之后,继续执行其后的代码。而wait()方法则会立即释放锁,然后当wait()暂停时间之后,回去重新争夺锁,然后再继续执行wait()之后的代码。