三个等待唤醒机制(wait-notify/notifyAll、await-signal、park-unpark)

一、wait-notify/notifyAll

public class Study {
    public static void main(String[] args) {
        Object o = new Object();

        new Thread(()->{
            synchronized (o){
                System.out.println("A即将被阻塞");

                try {
                    o.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println("A出来了");
            }
        },"A").start();


        new Thread(()->{
            synchronized (o){
                System.out.println("B要唤醒A了");
                o.notifyAll();
            }
        },"B").start();
    }
}

在这里插入图片描述

从以上代码可见,先wait()后notify(),A最后被唤醒了

如果先notify()后wait()呢?

public class Study {
    public static void main(String[] args) {
        Object o = new Object();

        new Thread(()->{
        //先睡眠2秒
            try {
                Thread.currentThread().sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (o){


                System.out.println("A即将被阻塞");

                try {
                    o.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println("A出来了");
            }
        },"A").start();


        new Thread(()->{
            synchronized (o){
                System.out.println("B要唤醒A了");
                o.notifyAll();
            }
        },"B").start();
    }
}

在这里插入图片描述
可见A没有被唤醒
以上可总结出wait-notify的两个缺点?
①必须与synchronized一起用
②必须执行wait()方法的线程先执行,执行notify()方法的线程后执行;

二、await-signal

public class Study {
    public static void main(String[] args) {
        ReentrantLock reentrantLock = new ReentrantLock();
        Condition condition =reentrantLock.newCondition();

        new Thread(()->{
            reentrantLock.lock();
            try{
                System.out.println("A要被阻塞了");
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("A被唤醒了");
            }finally {
                reentrantLock.unlock();
            }
        },"A").start();

        new Thread(()->{
            reentrantLock.lock();
            try{
                System.out.println("B要唤醒A了");
                try {
                    condition.signal();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }finally {
                reentrantLock.unlock();
            }
        },"B").start();

        
    }
}

在这里插入图片描述
从以上代码可见,先await()后signal(),线程A被唤醒了

那么先signal()后await(),会是啥呢?

public class Study {
    public static void main(String[] args) {
        ReentrantLock reentrantLock = new ReentrantLock();
        Condition condition =reentrantLock.newCondition();

        new Thread(()->{
        //睡眠2秒让执行signal()的线程先执行
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            reentrantLock.lock();
            try{
                System.out.println("A要被阻塞了");
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("A被唤醒了");
            }finally {
                reentrantLock.unlock();
            }
        },"A").start();

        new Thread(()->{
            reentrantLock.lock();
            try{
                System.out.println("B要唤醒A了");
                try {
                    condition.signal();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }finally {
                reentrantLock.unlock();
            }
        },"B").start();


    }
}

在这里插入图片描述
以上可见 await-signal的缺点:
①要依赖与ReentrantLock锁
②signal先于await执行会导致阻塞

三.park-unpark

在这里插入图片描述

public class Study {
    public static void main(String[] args) {
        Thread A = new Thread(()-> {
            System.out.println("A线程要被阻塞了");
            LockSupport.park();
            System.out.println("A线程出来了");
        });
        A.start();

        new Thread(()->{
            System.out.println("B要唤醒A了");
            LockSupport.unpark(A);
        },"B").start();


    }
}

以上代码可见,线程A被B唤醒了

那么我们先执行拥有unpark()方法的B线程,结果又会是怎样呢?

public class Study {
    public static void main(String[] args) {
        Thread A = new Thread(()-> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("A线程要被阻塞了");
            LockSupport.park();
            System.out.println("A线程出来了");
        });
        A.start();

        new Thread(()->{
            System.out.println("B要唤醒A了");
            LockSupport.unpark(A);
        },"B").start();


    }
}

在这里插入图片描述
可见即使先执行了unpark(),A还是被唤醒了

以上可见,park-unpark的优点是:
①不相wait…要依赖synchronized、await…要依赖 ReentrantLock,,这个只需要调用LockSupport的静态方法即可,十分方便
②即使先执行了unpark()最终A还是被唤醒,可以避免因为线程的启动顺序导致线程阻塞

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值