线程的通知与等待机制

116 阅读2分钟

复习时可参考JUC脑图,时间关系,先不整理这款代码实现

三种线程通知与等待的方法

  1. 使用Object中的wait()方法让线程等待,使用Object中的notify() / notifAll()方法通知线程
    注意:在执行notify方法后,当前线程不会马上释放该对象锁,处于wait状态的线程也不能马上获取该对象锁。要等到执行notify方法的线程将程序执行完,也就是退出synchronized代码块后,当前线程才会释放锁

Java中的Object类是所有类的父类,Object类包含所有子类需要的方法,如wait/notify/notifyAll等方法

  1. 使用JUC包中Condition的await()方法让线程等待,使用signal() / signalAll()方法通知线程
  2. LockSupport类中的park阻塞当前线程以及upark唤醒指定被阻塞的线程

Object类相关API

假设共享变量为Object obj = new Object();

wait

  • 什么时候会阻塞?
    当一个线程t1调用共享变量obj的wait()方法时,该线程t1会被阻塞
  • 什么时候会从阻塞状态变为非阻塞状态?
    其他线程main 调用该共享变量obj的nofify()或notifyAll()方法
    其他线程main 调用该线程t1的interrupt()方法,该线程t1会抛InterruptedException异常返回。
public class WaitNotifyInterrupt {

    static Object object = new Object();
    
    public static void main(String[] args) {
        Thread t1 = new Thread(()->{
            System.out.println("t1 begin");
            synchronized (object) {
                try {
                    object.wait();
                    System.out.println("t1 end");//中断后,这行代码不执行
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        
        t1.start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("main start. interrupt t1");
        t1.interrupt();
        System.out.println("main end. interrupt t1");
    }
    
}

执行结果: image.png

wait(long timeout)

如果一个线程t1调用共享对象obj的wait(3000)方法后,也就是3秒内如果还没有被其他线程main对该共享变量obj的notify或notifyAll调用,那么wait(3000)会3秒后不会阻塞,继续往下执行

public class WaitNotifyInterrupt2 {

    static Object object = new Object();
    
    public static void main(String[] args) {
        Thread t1 = new Thread(()->{
            System.out.println("t1 begin");
            synchronized (object) {
                try {
                    object.wait(3000);
                    System.out.println("t1 end");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t1.start();
    }
}
执行结果:
t1 begin
t1 end   //3秒后执行

notify()

一个线程调用共享对象的notify方法后,会唤醒一个在该共享变量上调用wait系列方法后的线程。一个共享变量可能会有多个线程在等待,具体唤醒哪个等待的线程是随机的。
注意:被唤醒后的线程,必须在获取共享变量的监视器锁后才能真正解除阻塞状态。被唤醒后的线程,还是需要与其他线程一起竞争该锁

notifyAll()

唤醒所有在该共享变量上调用wait系列方法后处于阻塞状态的线程。