• 恶补多线程编程实践4之ReentrantLock的使用以及condition


    ReentrantLock也是一种可重入锁,类似于synchronized,也就是在拥有锁的情况下可以调用其它需要本锁的方法或者代码块。lock.getHoldCount()可以获得当前线程拥有锁的层数,可以理解为重入了几层。当为0的时候代表当前线程没有占用锁,每重入一次count就加1.

    基本的使用方法

    调用其lock()方法会占用锁,调用unlock()会释放锁,但是需要注意必须手动unlock释放锁,否则其他线程会永远阻塞。而且发生异常不会自动释放锁,所以编写程序的时候需要在finally中手动释放锁。**

    //普通的加锁解锁过程
    public class application_ReentrantLock {
        public static void main(String[] args) {
            ReentrantLock lock = new ReentrantLock();
            ExecutorService service  = Executors.newFixedThreadPool(2);
            for (int i=0;i<2;i++){
                Runnable runnable = new Runnable() {
                    @Override
                    public void run() {
                        try {
                            System.out.println(Thread.currentThread().getName()+"开始执行");
                            lock.lock();//ReentrantLock进行加锁
                            System.out.println(Thread.currentThread().getName()+"加锁");
                            Thread.sleep(1000);
                            lock.unlock();
                            System.out.println(Thread.currentThread().getName()+"解锁,结束");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
    
                    }
                };
                service.execute(runnable);
            }
            service.shutdown();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    使用Condition实现等待/通知

    关键字synchronized与wait()/notify()、notifyAll()方法相结合可以实现等待/通知模式,类ReentrantLock也可以实现类似的功能,但需要借助于Condition对象。Condition类是JDK5中出现的类,使用它有更好的灵活性,比如可以实现多路通知功能,也就是在一个Lock对象里面可以创建多个Condition(即对象监视器实例),线程对象可以注册在指定的Condition中,从而可以有选择性地进行线程通知,在调度线程上更加灵活。

    在使用notify()/notifyAll()方法进行通知时,被通知的线程却是由JVM随机选择的。但使用ReentrantLock结合Condition类是可以实现前面介绍过的"选择性通知",这个功能是非常重要的,而且在Condition类中是默认提供的。

    而synchronized就相当于整个Lock对象中只有一个单一的Condition对象,所有的线程都注册在它一个对象的身上。线程开始notifyAll()时,需要通知所有的WATING线程,没有选择权,会出现相当大的效率问题。

    condition对象的await()\signal()\signalAll()必须在获得lock.lock()占用锁之后调用,而且最后必须手动释放锁。

    Condition的await()方法相当于Object的wait()方法,会释放锁;

    Condition的signal()方法相当于Object类的notify()方法,Condition类的signalAll()方法相当于Object的notifyAll()方法,会唤醒对应的await()线程。

    //ReentrantLock結合Condition实现等待/通知
    //condition对象的await()\signal()\signalAll()
    // 必须在获得lock.lock()占用锁之后调用,而且最后必须手动释放锁。
    class application_ReentrantLock1 {
        public static void main(String[] args) {
            ReentrantLock lock = new ReentrantLock();
            Condition condition = lock.newCondition();
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        lock.lock();
                        System.out.println(Thread.currentThread().getName()+"start await");
                        condition.await();//Condition的await()方法相当于Object的wait()方法,会释放锁;
                        System.out.println(Thread.currentThread().getName()+"end await");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }finally {
                        System.out.println(Thread.currentThread().getName()+"unlock");
                        lock.unlock();
                    }
                }
            });
    
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        lock.lock();
                        System.out.println(Thread.currentThread().getName()+"start signal");
                        condition.signal();//signal()方法,会唤醒对应的await()线程。
                        System.out.println(Thread.currentThread().getName()+"end signal");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }finally {
                        System.out.println(Thread.currentThread().getName()+"unlock");
                        lock.unlock();
                    }
                }
            });
    
            t1.start();
            t2.start();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    使用多个Condition实现等待/通知部分线程

    使用ReentrantLock创建多个Condition对象之后可以实现唤醒指定的线程,这是控制部分线程行为的方便方式。可以理解为将线程分组,每一组对应一个condition对象。

    //使用多个Condition实现等待/通知部分线程
    class application_ReentrantLock2 {
        public static void main(String[] args) {
            ReentrantLock lock = new ReentrantLock();
            Condition conditionA = lock.newCondition();
            Condition conditionB = lock.newCondition();
    
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        lock.lock();
                        System.out.println(Thread.currentThread().getName()+"start await");
                        conditionA.await();//Condition的await()方法相当于Object的wait()方法,会释放锁;
                        System.out.println(Thread.currentThread().getName()+"end await");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }finally {
                        System.out.println(Thread.currentThread().getName()+"unlock");
                        lock.unlock();
                    }
                }
            });
    
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        lock.lock();
                        System.out.println(Thread.currentThread().getName()+"start signal");
                        conditionA.signal();//signal()方法,会唤醒对应的await()线程。
                        System.out.println(Thread.currentThread().getName()+"end signal");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }finally {
                        System.out.println(Thread.currentThread().getName()+"unlock");
                        lock.unlock();
                    }
                }
            });
    
            Thread t3 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        lock.lock();
                        System.out.println(Thread.currentThread().getName()+"start await");
                        conditionB.await();//Condition的await()方法相当于Object的wait()方法,会释放锁;
                        System.out.println(Thread.currentThread().getName()+"end await");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }finally {
                        System.out.println(Thread.currentThread().getName()+"unlock");
                        lock.unlock();
                    }
                }
            });
    
            Thread t4 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        lock.lock();
                        System.out.println(Thread.currentThread().getName()+"start signal");
                        conditionB.signal();//signal()方法,会唤醒对应的await()线程。
                        System.out.println(Thread.currentThread().getName()+"end signal");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }finally {
                        System.out.println(Thread.currentThread().getName()+"unlock");
                        lock.unlock();
                    }
                }
            });
    
            t1.start();
            t2.start();
            t3.start();
            t4.start();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81

    使用condition实现线程按顺序执行

    //使用condition实现线程按顺序执行
    class application_ReentrantLock3 {
        volatile static int currentNum = 1;
        public static void main(String[] args) {
            ReentrantLock lock = new ReentrantLock();
            Condition condition = lock.newCondition();
    
    
            for (int i=0;i<10;i++){
                Thread t = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            lock.lock();
                            while (!String.valueOf(currentNum).equals(Thread.currentThread().getName())){
                                condition.await();//释放锁资源 然后等待
                            }
                            System.out.println(currentNum);
                            condition.signalAll();
                            currentNum++;
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }finally {
                            lock.unlock();
                        }
                    }
                },(i+1)+"");
    
                t.start();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
  • 相关阅读:
    react native 使用react-native-web运行在web端(自定义webpack.config.js配置篇)
    Matlab 中值滤波原理分析
    Python爬虫抢购某宝秒杀商品
    Hive案例
    Django viewsets 视图集与 router 路由实现评论接口开发
    goLang小案例-获取从控制台输入的信息
    云原生 | Kubernetes - Helm - Prometheus 实现资源限制
    将python两个版本添加环境变量(Mac版)
    常见工具指令【Vim | GIT | ZIP | UNZIP | IDEA】
    KWin、libdrm、DRM从上到下全过程 —— drmModeAddFBxxx(3)
  • 原文地址:https://blog.csdn.net/Oblak_ZY/article/details/125997468