> 文章列表 > wait()、sleep()、notify()的解析

wait()、sleep()、notify()的解析

wait()、sleep()、notify()的解析

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();}
}

wait()、sleep()、notify()的解析

【注意事项】:必须持有该锁,才能操作锁。

通过上述代码得到以下结论:

  1. 上述线程1内调用了wait()方法后,线程2就抢到锁了。➡️wait()会释放cpu资源,释放锁;
  2. 上述线程2内调用了sleep(5000)方法后,线程3并没有抢到锁。➡️ sleep()会释放cpu资源,不会释放锁;
  3. 上述线程2内调用了notify()方法后,线程1执行了 ➡️ notify()会随机唤醒一个线程;notifyAll()会唤醒所有线程。
  4. sleep()Thread 类的静态本地方法,wait() 则是 Object 类的本地方法。

上述题目答案:

【问题1】:🔔wait()、sleep()、notify()有什么作用?

  • wait():让线程等待,使其暂停执行
  • sleep():让线程休眠,使其暂停执行
  • notify():唤醒正在等待的线程

【问题2】:🔔wait()、sleep()的区别?

  • wait():
    1. 会释放cpu资源、锁资源
    2. 线程不会自动苏醒,需要别的线程调用同一个对象上的 notify()或者 notifyAll() 方法,或者也可以使用 wait(long timeout) 超时后线程会自动苏醒
  • sleep():
    1. 会释放cpu资源
    2. 时间到了后线程会自动苏醒

【问题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() 方法