• 3种唤醒的应用


    固定运行顺序

    比如,必须先 2 后 1 打印
    wait notify 版

    /**
     * @author WGR
     * @create 2021/2/1 -- 14:16
     */
    @Slf4j(topic = "c.Test25")
    public class Test25 {
        static final Object lock = new Object();
        // 表示 t2 是否运行过
        static boolean t2runned = false;
    
        public static void main(String[] args) {
            Thread t1 = new Thread(() -> {
                synchronized (lock) {
                    while (!t2runned) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    log.debug("1");
                }
            }, "t1");
    
    
            Thread t2 = new Thread(() -> {
                synchronized (lock) {
                    log.debug("2");
                    t2runned = true;
                    lock.notify();
                }
            }, "t2");
    
            t1.start();
            t2.start();
        }
    }
    
    

    Park Unpark 版
    可以看到,实现上很麻烦:首先,需要保证先 wait 再 notify,否则 wait 线程永远得不到唤醒。因此使用了『运行标记』来判断该不该wait
    第二,如果有些干扰线程错误地 notify 了 wait 线程,条件不满足时还要重新等待,使用了 while 循环来解决最后,唤醒对象上的 wait 线程需要使用 notifyAll,因为『同步对象』上的等待线程可能不止一个可以使用 LockSupport 类的 park 和 unpark 来简化上面的题目:

    
    /**
     * @author WGR
     * @create 2021/2/1 -- 14:18
     */
    @Slf4j(topic = "c.Test26")
    public class Test26 {
        public static void main(String[] args) {
    
            Thread t1 = new Thread(() -> {
                LockSupport.park();
                log.debug("1");
            }, "t1");
            t1.start();
    
            new Thread(() -> {
                log.debug("2");
                LockSupport.unpark(t1);
            },"t2").start();
        }
    }
    

    park 和 unpark 方法比较灵活,他俩谁先调用,谁后调用无所谓。并且是以线程为单位进行『暂停』和『恢复』,
    不需要『同步对象』和『运行标记』

    Condition 版

    /**
     * @author WGR
     * @create 2021/2/1 -- 14:41
     */
    @Slf4j(topic = "c.Test28")
    public class Test28 {
    
        public static void main(String[] args) {
    
            ReentrantLock reentrantLock = new ReentrantLock();
            Condition condition = reentrantLock.newCondition();
    
            Thread t1 = new Thread(() -> {
                reentrantLock.lock();
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    reentrantLock.unlock();
                }
                log.debug("1");
            }, "t1");
            t1.start();
    
            new Thread(() -> {
                reentrantLock.lock();
                try{
                    log.debug("2");
                    condition.signal();
                }finally {
                    reentrantLock.unlock();
                }
    
    
            },"t2").start();
        }
    }
    
    

    交替输出

    线程 1 输出 a 5 次,线程 2 输出 b 5 次,线程 3 输出 c 5 次。现在要求输出 abcabcabcabcabc 怎么实现
    wait notify 版

    
    /**
     * @author WGR
     * @create 2021/2/1 -- 14:26
     */
    @Slf4j(topic = "c.Test27")
    public class Test27 {
        public static void main(String[] args) {
            WaitNotify wn = new WaitNotify(1, 5);
            new Thread(() -> {
                wn.print("a", 1, 2);
            }).start();
            new Thread(() -> {
                wn.print("b", 2, 3);
            }).start();
            new Thread(() -> {
                wn.print("c", 3, 1);
            }).start();
        }
    }
    
    /*
    输出内容       等待标记     下一个标记
       a           1             2
       b           2             3
       c           3             1
     */
    class WaitNotify {
        // 打印               a           1             2
        public void print(String str, int waitFlag, int nextFlag) {
            for (int i = 0; i < loopNumber; i++) {
                synchronized (this) {
                    while(flag != waitFlag) {
                        try {
                            this.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.print(str);
                    flag = nextFlag;
                    this.notifyAll();
                }
            }
        }
    
        // 等待标记
        private int flag; // 2
        // 循环次数
        private int loopNumber;
    
        public WaitNotify(int flag, int loopNumber) {
            this.flag = flag;
            this.loopNumber = loopNumber;
        }
    }
    

    Park Unpark 版

    /**
     * @author WGR
     * @create 2021/2/1 -- 14:30
     */
    @Slf4j(topic = "c.Test31")
    public class Test31 {
    
        static Thread t1;
        static Thread t2;
        static Thread t3;
        public static void main(String[] args) {
            ParkUnpark pu = new ParkUnpark(5);
            t1 = new Thread(() -> {
                pu.print("a", t2);
            });
            t2 = new Thread(() -> {
                pu.print("b", t3);
            });
            t3 = new Thread(() -> {
                pu.print("c", t1);
            });
            t1.start();
            t2.start();
            t3.start();
    
            LockSupport.unpark(t1);
        }
    }
    
    class ParkUnpark {
        public void print(String str, Thread next) {
            for (int i = 0; i < loopNumber; i++) {
                LockSupport.park();
                System.out.print(str);
                LockSupport.unpark(next);
            }
        }
    
        private int loopNumber;
    
        public ParkUnpark(int loopNumber) {
            this.loopNumber = loopNumber;
        }
    }
    

    Condition 版

    /**
     * @author WGR
     * @create 2021/2/1 -- 14:35
     */
    public class Test30 {
        public static void main(String[] args) throws InterruptedException {
            AwaitSignal awaitSignal = new AwaitSignal(5);
            Condition a = awaitSignal.newCondition();
            Condition b = awaitSignal.newCondition();
            Condition c = awaitSignal.newCondition();
            new Thread(() -> {
                awaitSignal.print("a", a, b);
            }).start();
            new Thread(() -> {
                awaitSignal.print("b", b, c);
            }).start();
            new Thread(() -> {
                awaitSignal.print("c", c, a);
            }).start();
    
            Thread.sleep(1000);
            awaitSignal.lock();
            try {
                System.out.println("开始...");
                a.signal();
            } finally {
                awaitSignal.unlock();
            }
    
        }
    }
    
    class AwaitSignal extends ReentrantLock {
        private int loopNumber;
    
        public AwaitSignal(int loopNumber) {
            this.loopNumber = loopNumber;
        }
        //            参数1 打印内容, 参数2 进入哪一间休息室, 参数3 下一间休息室
        public void print(String str, Condition current, Condition next) {
            for (int i = 0; i < loopNumber; i++) {
                lock();
                try {
                    current.await();
                    System.out.print(str);
                    next.signal();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    unlock();
                }
            }
        }
    }
    
  • 相关阅读:
    unity-TextAsset
    unity-热更-InjectFix
    进程和线程的区别
    StringBuffer 和 StringBuilder 的区别
    List、Set、Map 三者区别
    竞态条件是什么?
    多线程安全(synchronized、三大特性、生命周期以及优缺点)
    集合的同步与非同步
    List、Set、Map的了解及区别
    java面试题
  • 原文地址:https://www.cnblogs.com/dalianpai/p/14356710.html
Copyright © 2020-2023  润新知