三个等待唤醒机制(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/notifyAll、await-signal、park-unpark)_第1张图片

从以上代码可见,先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();

        
    }
}

三个等待唤醒机制(wait-notify/notifyAll、await-signal、park-unpark)_第2张图片
从以上代码可见,先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();


    }
}

三个等待唤醒机制(wait-notify/notifyAll、await-signal、park-unpark)_第3张图片
以上可见 await-signal的缺点:
①要依赖与ReentrantLock锁
②signal先于await执行会导致阻塞

三.park-unpark

三个等待唤醒机制(wait-notify/notifyAll、await-signal、park-unpark)_第4张图片

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


    }
}

三个等待唤醒机制(wait-notify/notifyAll、await-signal、park-unpark)_第5张图片
可见即使先执行了unpark(),A还是被唤醒了

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

你可能感兴趣的:(JUC,java,rust,scala)