zoukankan      html  css  js  c++  java
  • 并发包(JUC)之Condition、CountDownLatch

    Condition

    1、Condition概述

      对于synchronized,可以结合wait/notify实现线程的通信,Condition则是JUC中提供的一个多线程协调通信的工具类,可以让某些线程等待某个条件(condition),只有满足条件时才会被唤醒。

      condition.await( )和condition.signal( )使用示例:和wait/notify一样,await/signal也要在lock( )和unlock( )之间使用。

    public class ConditionDemoWait implements  
    Runnable{ 
     
        private Lock lock; 
        private Condition condition; 
        public ConditionDemoWait(Lock lock, 
    Condition condition){ 
            this.lock=lock; 
            this.condition=condition; 
        } 
     
        @Override 
        public void run() { 
            System.out.println("begin 
    ConditionDemoWait"); 
            try { 
                lock.lock(); 
                condition.await(); 
                System.out.println("end - 
    ConditionDemoWait"); 
            } catch (InterruptedException e) { 
                e.printStackTrace(); 
            }finally { 
                lock.unlock(); 
            } 
        } 
    }
    public class ConditionDemoSignal implements  
    Runnable{ 
     
        private Lock lock; 
        private Condition condition; 
        public ConditionDemoSignal(Lock lock, 
    Condition condition){ 
            this.lock=lock; 
            this.condition=condition; 
        } 
     
        @Override 
        public void run() { 
            System.out.println("begin 
    ConditionDemoSignal"); 
            try { 
                lock.lock(); 
                condition.signal(); 
                System.out.println("end - 
    ConditionDemoSignal"); 
            }finally { 
                lock.unlock(); 
            } 
        } 
    } 

     2、Condition原理分析

      调用Condition,需要获得Lock锁,所以意味着会存在一 个AQS同步队列,而Condition也是通过AbstractQueuedSynchronizer内部的ConditionObject具体实现的,其内部维护一个单向链表(也成为Condition队列)。

                                     

       假设有线程A和线程B状态如下:

                 

    (1)当在线程A中调用condition.await( ),将ThreadA封装成Node节点(waitStatus=CONDITION),将Node添加到Condition队列尾部,然后释放锁(此时AQS中state=0),通过LockSupport.park( )阻塞在调用处。此时AQS队列挂起的线程被唤醒竞争锁。

    (2)当在线程B中调用condition.signal( )(注意要和A中调用的condition为同一个对象),将Condition队列的头节点通过CAS添加到AQS队列的尾部,firstWaiter指向原头节点的后继节点,此时原头节点有资格去竞争锁。

                 

    CountDownLatch 

    1、CountDownLatch(共享锁)  

      countdownlatch是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程做操作执行完。提供了两个方法,一个是await( ),一个是countDown( ),countdownlatch初始化时需要传入一个整数,在这个整数倒数到0之前,调用了await方法的线程都要等待,然后通过countDwon方法来倒数。

      使用示例:

    public class Demo extends Thread{

    static CountDownLatch countDownLatch=new CountDownLatch(1);
    @Override public void run() {
    try {
    countDownLatch.await();
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }

    public static void main(String[] args) throws InterruptedException {
    for(int i=0;i<1000;i++){
    new Demo().start();
    }
    countDownLatch.countDown();
    }
    }

      从示例可以看出,countDownLatch可以做压测。每次调用countDown( ),state会减1,当state减到0时之前调用await阻塞的线程都被唤醒执行。

    2、CountDownLatch原理  

      countDownLatch也使用到了AQS队列,当一个线程内调用await( )时,会将该节点封装成Node(waitStatus=PROPAGATE,共享模式下才节点才会处于这个状态,处于这个状态下的节点,会对线程的唤醒进行传播)添加到AQS队列中,并为阻塞状态。当倒数到state=0时,会从头节点依次唤醒AQS队列中的所有节点。

          

    其他工具类:

    1、Semaphore,可以控制同时访问的线程个数,常用于限流功能。

      使用示例:

    public class Test { 
        public static void main(String[] args) { 
            Semaphore semaphore=new Semaphore(5); 
            for(int i=0;i<10;i++){ 
                new Car(i,semaphore).start(); 
            } 
        } 
        static class Car extends Thread{ 
            private int num; 
            private Semaphore semaphore; 
     
            public Car(int num, Semaphore 
    semaphore) { 
                this.num = num; 
                this.semaphore = semaphore; 
            } 
            public void run(){ 
                try { 
                    semaphore.acquire();// 获取一个许可
     
                    System.out.println("第"+num+"占用
    一个停车位"); 
                    TimeUnit.SECONDS.sleep(2); 
                    System.out.println("第"+num+"俩车
    走喽"); 
                    semaphore.release(); 
                } catch (InterruptedException e) { 
                    e.printStackTrace(); 
                } 
            } 
        } 
    } 

    2、CyclicBarrier,可循环使用的屏障,让一组线程到达一个屏障时被阻塞,直到最后一个线程到达屏障时,屏障才会打开,所有被屏障拦截的线程才会继续工作。

  • 相关阅读:
    CentOS/RHEL 查看用户登陆信息
    PAM
    块存储
    ECS
    SQL 基础应用
    MySQL 基础管理
    MySQL 体系结构
    JSON对象
    设置dom节点属性的代码优化
    Ext框架下的元素拖动
  • 原文地址:https://www.cnblogs.com/jing-yi/p/12768689.html
Copyright © 2011-2022 走看看