线程的 sleep() 方法与 wait() 方法的区别
原创
©著作权归作者所有:来自51CTO博客作者程序员啊的原创作品,请联系作者获取转载授权,否则将追究法律责任
总的来说,线程的 sleep() 方法和 wait() 方法有以下几点区别:
(1)sleep() 方法是 Thread 类中的方法,而 wait() 方法是 Object 类中的方法。
(2)sleep() 方法不会释放 lock,但是 wait() 方法会释放,而且会加入到等待队列中。
(3)sleep() 方法不依赖于同步器 synchronized(),但是 wait() 方法 需要依赖 synchronized 关键字。
(4)线程调用 sleep() 之后不需要被唤醒(休眠时开始阻塞,线程的监控状态依然保持着,当指定的休眠时间到了就会自动恢复运行状态),但是 wait() 方法需要被重新唤醒(不指定时间需要被别人中断)。
public class SleepDemo {
public static final Object LOCK = new Object();
public static void main(String[] args) {
Stream.of("线程1", "线程2").forEach(a -> new Thread(a) {
@Override
public void run() {
new SleepDemo().testSleep();
}
}.start());
}
private void testSleep() {
synchronized (LOCK) {
try {
System.out.println(Thread.currentThread().getName() + "正在执行: " + System.currentTimeMillis() / 1000);
// 休眠 2 s
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + "恢复执行: " + System.currentTimeMillis() / 1000);
} catch (Exception e) {
}
}
}
}
可以看到,线程 1 先抢到了资源,执行主体方法时要求睡眠 2 秒,那么在这两秒时间内,即使线程 1 没有任何动作,线程 2 也不能抢占资源。 需要注意的是,在调用 sleep() 方法时,如果有两个线程,那么要想实现线程睡眠的效果就需要使用 synchronized() 方法,否则达不到效果。
public class SleepDemo {
// public static final Object LOCK = new Object();
public static void main(String[] args) {
Stream.of("线程1", "线程2").forEach(a -> new Thread(a) {
@Override
public void run() {
new SleepDemo().testSleep();
}
}.start());
}
private void testSleep() {
// synchronized (LOCK) {
try {
System.out.println(Thread.currentThread().getName() + "正在执行: " + System.currentTimeMillis() / 1000);
// 休眠 2 s
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + "恢复执行: " + System.currentTimeMillis() / 1000);
} catch (Exception e) {
System.out.println(e);
}
// }
}
}
如上所示,不使用 synchronized() 的话就会出现两个线程同时执行,同时睡眠,又同时恢复执行。
由此可知,调用 sleep() 方法时,并不是强依赖于 synchronized() 方法,如果我只有一个线程,那么使用 synchronized() 方法和不使用 synchronized() 方法的效果是一样的。如果有两个线程的话,也可以选择使用或者不使用 synchronized() 方法。但是 wait() 方法就不一样了,wait() 方法强依赖于 synchronized() 方法,如果不使用 synchronized() 方法的话,wait() 方法的程序就会报错。
public class WaitDemo {
public static final Object LOCK = new Object();
public static void main(String[] args) {
Stream.of("线程1", "线程2").forEach(a -> new Thread(a) {
@Override
public void run() {
WaitDemo.testWait();
}
}.start());
}
private static void testWait() {
// synchronized (LOCK) {
try {
System.out.println(Thread.currentThread().getName() + "正在执行: " + System.currentTimeMillis() / 1000);
// 等待 2 s
LOCK.wait(2000);
System.out.println(Thread.currentThread().getName() + "恢复执行: " + System.currentTimeMillis() / 1000);
} catch (InterruptedException e) {
System.out.println(e);
}
}
// }
}
使用 synchronized 关键字修饰后:
public class WaitDemo {
public static final Object LOCK = new Object();
public static void main(String[] args) {
Stream.of("线程1", "线程2").forEach(a -> new Thread(a) {
@Override
public void run() {
WaitDemo.testWait();
}
}.start());
}
private static void testWait() {
synchronized (LOCK) {
try {
System.out.println(Thread.currentThread().getName() + "正在执行: " + System.currentTimeMillis() / 1000);
// 等待 2 s
LOCK.wait(2000);
System.out.println(Thread.currentThread().getName() + "恢复执行: " + System.currentTimeMillis() / 1000);
} catch (InterruptedException e) {
System.out.println(e);
}
}
}
}
因为在代码中有指定 wait(2000),所以当 2 秒之后该线程就会恢复执行的,而不用另外一个线程去唤醒,如果 wait() 方法没有指定时间的话,那么该线程就会一直等待~
除此之外,一个线程一旦被 wait 之后,就必须有另外一个线程去唤醒,否则一直处于等待状态。
public class WaitDemo {
public static final Object LOCK = new Object();
private void testWait1() {
synchronized (LOCK) {
try {
System.out.println(Thread.currentThread().getName() + "开始执行: " + System.currentTimeMillis() / 1000);
LOCK.wait();
System.out.println(Thread.currentThread().getName() + "恢复执行: " + System.currentTimeMillis() / 1000);
} catch (Exception e) {
System.out.println(e);
}
}
}
private void testNotify() {
synchronized (LOCK) {
try {
Thread.sleep(2000);
LOCK.notify();
System.out.println(Thread.currentThread().getName() + "唤醒另一线程: " + System.currentTimeMillis() / 1000);
} catch (Exception e) {
System.out.println(e);
}
}
}
public static void main(String[] args) {
new Thread() {
@Override
public void run() {
new WaitDemo().testWait1();
}
}.start();
new Thread() {
@Override
public void run() {
new WaitDemo().testNotify();
}
}.start();
}
}