zoukankan      html  css  js  c++  java
  • JUC_01 线程阻塞、唤醒三种方式

    三种方式总结:
    
    一、synchronized: wait、notify、notifyAll
          1、需要结合synchronized使用,否作会出现异常
          2、必须先执行wait, 后执行notify或者notifyAll,否作会一直处于阻塞状态           
    二、Lock.condition:  await、signal、signalAll
          1、需要结合lock使用,否作会出现异常
          2、必须先执行await, 后执行signal或者signalAll, 否作会一直处于阻塞状态
    三、LockSupport: park、unpark
          1、不依赖其它外部代码
          2、park、unpark执行没有先后顺序
          3、unpark方法同一时间最多只能获取一个许可证,只能通知一个park方法
    package com.scwyfy.knowledge.juc;
    
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.LockSupport;
    import java.util.concurrent.locks.ReentrantLock;
    
    /**
     * LockSupport:park()与unpark() 用来阻塞和唤醒线程,不需要手动加锁即可实现,且对阻塞、唤醒顺序无要求
     *              注意: 执行多次unpark(),最多也只能获取一个许可证(不会进行累加操作),只能唤醒一个park()
     *              例如:先执行两次unpark(),再执行两次park(), 第二个park()将会处于阻塞状态
     * Synchronized: wait()与notify()或者notifyAll 用于阻塞和唤醒线程,需要结合Synchronized一起使用,否则将会产生异常 IllegalMonitorStateException
     *               且必须先wait(),再notify()。不然将会一直处于阻塞状态
     * Lock
     *  Condition: await()与signal()或者signalAll 用于阻塞和唤醒线程,需要结合Lock一起使用,否则将会产生异常 IllegalMonitorStateException
     *               且必须先await(),再signal()。不然将会一直处于阻塞状态
     */
    public class LockSupportDemo {
    
    
    
        public static void main(String[] args) {
    //        synchronizedSolution();
    //        lockSolution();
    //        lockSupportSolution();
            parkAndUnparkDemo();
    
        }
    
        /**
         * unpark方法:许可证最多只能有一个
         */
        private static void parkAndUnparkDemo() {
            Thread thread = new Thread(() -> {
                try {
                    TimeUnit.SECONDS.sleep(3L);// 目的先让执行unpark方法
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("准备执行两次park方法");
                LockSupport.park();
                System.out.println("已执行一次park方法");
                LockSupport.park();
                System.out.println("park方法执行完成");
            });
            thread.start();
            new Thread(() -> {
                System.out.println("准备执行两次unpark方法");
                LockSupport.unpark(thread);
                LockSupport.unpark(thread);
                System.out.println("unpark方法执行完成");
            }).start();
        }
    
        /**
         * LockSupport方式实现 阻塞、唤醒
         */
        private static void lockSupportSolution() {
            Thread a = new Thread(() -> {
                try {
                    TimeUnit.SECONDS.sleep(3L);
                    System.out.println(Thread.currentThread().getName() + " --- 进入");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                LockSupport.park(); // 不需要依赖外部代码,park与unpark方法不用区分先后执行顺序
                System.out.println(Thread.currentThread().getName() + " --- 出来");
            }, "a");
            a.start();
    
            Thread b = new Thread(() -> {
                LockSupport.unpark(a); // 不需要依赖外部代码,park与unpark方法不用区分先后执行顺序
                System.out.println(Thread.currentThread().getName() + " --- 通知");
            }, "b");
            b.start();
        }
    
        /**
         * Lock.Condition方式实现阻塞、唤醒
         */
        private static void lockSolution() {
            Lock lock = new ReentrantLock();
            Condition condition = lock.newCondition();
    
            new Thread(() -> {
                try {
    //                TimeUnit.SECONDS.sleep(3L);// 先signal,再await,会一直处于阻塞状态
                    lock.lock();
                    System.out.println(Thread.currentThread().getName() + " --- 进入");
                    condition.await(); // 不结合lock,await、signal方法会有异常IllegalMonitorStateException
                    System.out.println(Thread.currentThread().getName() + " --- 出来");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }, "A").start();
    
            new Thread(() -> {
                try {
                    lock.lock();
                    System.out.println(Thread.currentThread().getName() + " --- 通知");
                    condition.signal();
                } finally {
                    lock.unlock();
                }
            }, "B").start();
        }
    
        /**
         * synchronized方式实现阻塞、唤醒
         */
        private static void synchronizedSolution() {
            Object synchronizedLock = new Object();
            new Thread(() -> {
                try {
    //                TimeUnit.SECONDS.sleep(3L); // 先notify,再wait。会一直阻塞状态
                    synchronized (synchronizedLock) {// 不结合synchronized, wait、notify方法会有异常IllegalMonitorStateException
                        System.out.println(Thread.currentThread().getName() + " --- 进入");
                        synchronizedLock.wait();
                        System.out.println(Thread.currentThread().getName() + " --- 出来");
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, "A").start();
    
            new Thread(() -> {
               synchronized(synchronizedLock) {
                   synchronizedLock.notify();
                   System.out.println(Thread.currentThread().getName() + " --- 通知");
               }
            }, "B").start();
        }
    
    }
  • 相关阅读:
    TDiocpTcpServer socket哈希表
    TCrossSocket
    TDiocpCoderTcpServer和TDiocpTcpServer的关系和区别
    TDiocpTcpServer数据包大小
    cross socket tcp数据包最大长度
    在DLL中使用DevExpress
    cross socket tcp client demo
    nginx-proxy docker 的nginx自动服务发现方案
    golang used for two different module paths 问题解决
    grafana dashboard 分享的几种处理方法
  • 原文地址:https://www.cnblogs.com/yuefeng123/p/14750246.html
Copyright © 2011-2022 走看看