并发工具类CountDownLatch、CyclicBarrier(同步屏障)、Semaphore(控制并发线程数)、Exchanger(线程交换数据)

CountDownLatch

简介原理

  CountDownLatch是由队列同步器实现的。

  在构建新的CountDownLatch对象时,需要传入一个大于0的整形int参数。而这个参数就作为队列同步器的state同步状态了。

    public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }
        Sync(int count) {
            setState(count);
        }

  当一个线程在执行了CountDownLatch的 .await() 方法之后,会阻塞自旋判断state是否是0。而state是通过CountDownLatch的 .countDown() 方法来减少的。

    public void countDown() {
        sync.releaseShared(1);
    }

用法场景

  比如需要多线程汇算多个sheet,最后需要结果汇总,就可以在主线程那里执行await(),在每个sheet运算完了之后执行countDown()即可

CyclicBarrier

简介原理

  CyclicBarrier同步屏障有两种构造方法。

  第一种,参数只传整形数字。

    public CyclicBarrier(int parties) {
        this(parties, null);
    }

  第二种,参数还要传一个线程的实现

    public CyclicBarrier(int parties, Runnable barrierAction) {
        if (parties <= 0) throw new IllegalArgumentException();
        this.parties = parties;
        this.count = parties;
        this.barrierCommand = barrierAction;
    }

  CyclicBarrier是通过调用其 .await() 方法,对当前线程进行上锁,其内部有成员变量可重入锁。

  第一种:

  1.假设参数传2,线程执行await()方法,线程1先抢到锁,然后会对parties参数先减1,然后判断是否是0,是0则运行线程后面的逻辑了。

  2.如果不是0,则调用Condition的trip()方法,trip()方法会释放锁并等待。这时候线程2就可以抢到锁,然后执行第1步里的逻辑,这时候parties减1就是0了。这时候会调用Condition的signalAll()方法,通知trip()方法的线程可以继续执行了

  第二种:

  参数不仅传2,还传了另一个线程(别名取C)进来。其实大致逻辑和第一种差不多,只是在第1步判断了parties为0之后,会先去执行线程C的逻辑,再去唤醒另外两个线程。

用法场景

CountDownLatch与CyclicBarrier的区别

  个人理解, CountDownLatch 就像是军训教官让学员报数,等所有人(线程)报完数了之后,教官在他的小本本上记录人数并开始训话(. .await() )。而 CyclicBarrier 也像是军训让学员报数,而报数完了之后,学员立即去完成各自的任务,学员等待他人报数的过程就是从 .await() 开始的

Semaphore

简介原理

  构建Semaphore的时候需要整形参数,表示它最多允许多少个线程并行运行。

    public Semaphore(int permits) {
        sync = new NonfairSync(permits);
    }

  线程中需要执行 semaphore.acquire() 表示拿到许可证了,然后同步状态会响应变化,然后执行 sync.releaseShared(1) 表示释放许可证,其它线程可以获取许可证了

用法场景

  各种需要限制线程数量的场景。例如连接池场景,需要限制线程数。

Exchanger

用法场景

  线程间交换数据

posted on 2020-04-22 11:48  lyjlyjlyj  阅读(171)  评论(0编辑  收藏  举报

导航