并发编程之CountDownLatch,CyclicBarrier ,Semaphore

CountDownLatch

CountDownLatch 这个类在java.util.concurrent并发包下

这个类的作用使一个线程等到其他线程都执行完了在执行本线程、
CountDownLatch根据名字也可以看出来,它其实是一个计数器,数量是需要等待执行完线程的数量,没执行完一个线程数量减1,当数量为零的时候,表示所有需要等待的线程执行完毕了,那么等待的的线程就可以继续执行了!

说起来有点绕,其实一点也不复杂:

public static void main(String[] args) {
    final CountDownLatch latch = new CountDownLatch(5);

    ExecutorService service = Executors.newFixedThreadPool(10);
    for (int i = 0; i < 5; i++){
        service.execute(() -> {
            System.out.println("开始执行" + Thread.currentThread().getName());
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("执行完毕" + Thread.currentThread().getName());
            latch.countDown();
        });
    }

    try {
        latch.await();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("全部线程都执行完毕了,可以进行了");
}

初始化 CountDownLatch为5,定义执行了5个线程,每个线程等待3秒之后调用latch.countDown();表示-1,当5个线程全部执行完了之后,被latch.await();阻塞的线程开始执行了,

结果如下:

开始执行pool-1-thread-1
开始执行pool-1-thread-2
开始执行pool-1-thread-3
开始执行pool-1-thread-4
开始执行pool-1-thread-5
执行完毕pool-1-thread-2
执行完毕pool-1-thread-3
执行完毕pool-1-thread-1
执行完毕pool-1-thread-4
执行完毕pool-1-thread-5
全部线程都执行完毕了,可以进行了

CountDownLatch 还有个重载的await()方法:await(long timeout, TimeUnit unit) 表示的是超时时间,如果等到了规定的时间,其他的线程还没有执行完的话就不等了

CyclicBarrier

CyclicBarrier这个类也在java.util.concurrent并发包下
CyclicBarrier的作用是等到所有的线程同时到达指定的状态后在同时执行,比如:

 CyclicBarrier barrier = new CyclicBarrier(5);

    ExecutorService service = Executors.newFixedThreadPool(10);
    for (int i = 0; i < 5; i++){
        service.submit(()->{
            System.out.println(Thread.currentThread().getName() + "正在执行。。。。");
            try {
                Thread.sleep(3000);
                System.out.println(Thread.currentThread().getName() +  " 已经执行完了,等待其他线程执行完毕");
                barrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "后续的任务开始执行");
        });
    }
}

结果如下:

pool-1-thread-2正在执行。。。。
pool-1-thread-1正在执行。。。。
pool-1-thread-3正在执行。。。。
pool-1-thread-5正在执行。。。。
pool-1-thread-4正在执行。。。。
pool-1-thread-5 已经执行完了,等待其他线程执行完毕
pool-1-thread-2 已经执行完了,等待其他线程执行完毕
pool-1-thread-1 已经执行完了,等待其他线程执行完毕
pool-1-thread-3 已经执行完了,等待其他线程执行完毕
pool-1-thread-4 已经执行完了,等待其他线程执行完毕
pool-1-thread-3后续的任务开始执行
pool-1-thread-2后续的任务开始执行
pool-1-thread-4后续的任务开始执行
pool-1-thread-5后续的任务开始执行
pool-1-thread-1后续的任务开始执行

CyclicBarrier 有两个构造方法:

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

parties表示的是要等到多少个线程达到指定的状态之后去执行
Runnable barrierAction 第二个参数表示的时候线程们都达到了指定的状态之后,先执行barrierAction,然后在同时执行。就是都达到了指定的状态,然后进行一些额外的操作,比如:

public static void main(String[] args) {

    CyclicBarrier barrier = new CyclicBarrier(5, new Runnable() {
        @Override
        public void run() {
            System.out.println("需要进行一些别的操作!");
        }
    });

    ExecutorService service = Executors.newFixedThreadPool(10);
    for (int i = 0; i < 5; i++){
        service.submit(()->{
            System.out.println(Thread.currentThread().getName() + "正在执行。。。。");
            try {
                Thread.sleep(3000);
                System.out.println(Thread.currentThread().getName() +  " 已经执行完了,等待其他线程执行完毕");
                barrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "后续的任务开始执行");
        });
    }
}

结果如下:

pool-1-thread-1正在执行。。。。
pool-1-thread-2正在执行。。。。
pool-1-thread-3正在执行。。。。
pool-1-thread-4正在执行。。。。
pool-1-thread-5正在执行。。。。
pool-1-thread-3 已经执行完了,等待其他线程执行完毕
pool-1-thread-4 已经执行完了,等待其他线程执行完毕
pool-1-thread-2 已经执行完了,等待其他线程执行完毕
pool-1-thread-1 已经执行完了,等待其他线程执行完毕
pool-1-thread-5 已经执行完了,等待其他线程执行完毕
需要进行一些别的操作!
pool-1-thread-5后续的任务开始执行
pool-1-thread-3后续的任务开始执行
pool-1-thread-4后续的任务开始执行
pool-1-thread-1后续的任务开始执行
pool-1-thread-2后续的任务开始执行

barrier.await();还有另外一个重载的方法:

public int await(long timeout, TimeUnit unit)

和CountDownLatch类似,定义一个超时机制,表示如果到了时间可以不用等到所有的线程都到达某个状态,就开始执行。

需要注意是的是CyclicBarrier ,是可以重复使用的,要不让怎么会有Cyclic呢。就是当一轮线程执行完了之后,你可以继续调用awiat,进行新一轮的等待执行操作,但是CountDownLatch不可以!
CountDownLatch和CyclicBarrier侧重点不同,CountDownLatch侧重的是某些任务都执行完了,然后进行后续的操作。而CyclicBarrier表示的是当所有的线程都相互等待到某一个状态之后进行同时进行后续的操作!

Semaphore

Semaphore字面意思是信号量,表示的是同时有多少个线程开始执行:

ExecutorService pool = Executors.newFixedThreadPool(10);

Semaphore semaphore = new Semaphore(3);

for (int i = 0; i < 5; i++){
    pool.submit(()->{
        try {
            semaphore.acquire();
            System.out.println(Thread.currentThread().getName() + "获得线程的执行权");
            Thread.sleep(3000);
            System.out.println(Thread.currentThread().getName() + "执行完毕");
            semaphore.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
}

结果:

pool-1-thread-1获得线程的执行权
pool-1-thread-2获得线程的执行权
pool-1-thread-3获得线程的执行权
pool-1-thread-1执行完毕
pool-1-thread-3执行完毕
pool-1-thread-2执行完毕
pool-1-thread-4获得线程的执行权
pool-1-thread-5获得线程的执行权
pool-1-thread-5执行完毕
pool-1-thread-4执行完毕

因为semaphore初始化指定为3,表示只能有三个线程同时执行,所以只有等到线程执行完调用了release方法,第4第5个线程才可以执行。

再小的进步,乘以356天也会变的伟大!

欢迎关注我的公众号: 北风中独行的蜗牛
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章