wait()、sleep()、notify()的解析
- 【🎈问题1】:wait()、sleep()、notify()有什么作用?
- 【🎈问题2】:wait()、sleep()的区别?
- 【🎈问题3】:为什么 wait() 方法不定义在 Thread 中,sleep()却定义在线程中?
代码示例:创建三个线程
public class WaitAndNotifyTest {
public static final WaitAndNotifyTest MONITOR = new WaitAndNotifyTest();
public static void main(String[] args) {
new Thread(() -> {
synchronized (MONITOR) {
System.out.println("线程1开始了.....");
try {
System.out.println("线程1wait()了.....");
MONITOR.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("线程1结束了.....");
}
}).start();
new Thread(() -> {
synchronized (MONITOR) {
System.out.println("线程1wait(),线程2抢到锁,线程2开始了.....");
try {
System.out.println("线程2 sleep()5秒钟.....");
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("线程2唤醒notify().....");
MONITOR.notify();
System.out.println("线程2结束了.....");
}
}).start();
new Thread(() -> {
synchronized (MONITOR) {
System.out.println("线程3抢到锁,线程3开始了.....");
System.out.println("线程3结束了.....");
}
}).start();
}
}
【注意事项】:必须持有该锁,才能操作锁。
通过上述代码得到以下结论:
- 上述线程1内调用了
wait()
方法后,线程2就抢到锁了。➡️wait()
会释放cpu资源,释放锁; - 上述线程2内调用了
sleep(5000)
方法后,线程3并没有抢到锁。➡️sleep()
会释放cpu资源,不会释放锁; - 上述线程2内调用了
notify()
方法后,线程1执行了 ➡️notify()
会随机唤醒一个线程;notifyAll()
会唤醒所有线程。 sleep()
是Thread
类的静态本地方法,wait()
则是Object
类的本地方法。
上述题目答案:
【问题1】:🔔wait()、sleep()、notify()有什么作用?
- wait():让线程等待,使其暂停执行
- sleep():让线程休眠,使其暂停执行
- notify():唤醒正在等待的线程
【问题2】:🔔wait()、sleep()的区别?
- wait():
- 会释放cpu资源、锁资源
- 线程不会自动苏醒,需要别的线程调用同一个对象上的
notify()
或者notifyAll()
方法,或者也可以使用wait(long timeout)
超时后线程会自动苏醒
- sleep():
- 会释放cpu资源
- 时间到了后线程会自动苏醒
【问题3】:🔔为什么 wait() 方法不定义在 Thread 中,sleep()却定义在线程中?
wait() 方法的作用是让当前线程等待另一个线程发出的通知,并且必须在对象锁上下文中调用,所以它被定义在 Object 类中。
sleep() 方法是使当前线程暂停执行的方法,它不需要在锁上下文中调用,因此被定义在 Thread 类中。
【拓展】:🥤yield()方法:
yield()
方法是一个静态方法,调用它可以让当前线程让出 CPU,让 CPU 去执行其他线程。调用 yield()
方法并不会释放当前线程持有的锁。
yield()
方法的作用是让处于运行状态的线程转换到可运行状态,以便让其他线程也有机会运行,从而避免某些线程长时间占用 CPU 而导致其他线程无法执行的问题。但是,yield()
方法不能保证当前线程一定会让出 CPU,因为让出 CPU 的决定是由操作系统来决定的。
示例代码:
javaCopy codepublic class YieldExample implements Runnable {
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
Thread.yield();
}
}
public static void main(String[] args) {
YieldExample ye = new YieldExample();
Thread t1 = new Thread(ye, "Thread-1");
Thread t2 = new Thread(ye, "Thread-2");
t1.start();
t2.start();
}
}
运行结果可能如下:
makefileCopy codeThread-1: 1
Thread-2: 1
Thread-1: 2
Thread-2: 2
Thread-1: 3
Thread-2: 3
Thread-1: 4
Thread-2: 4
Thread-1: 5
Thread-2: 5
可以看到,两个线程轮流打印输出,因为每个线程在打印完一次后都调用了 yield()
方法