CountDownLatch、CyclicBarrier和Semaphore基本原理和使用

一、CountDownLatch

CountDownLatch类位于java.util.concurrent包下,利用它可以实现类似计数器的功能。
比如有一个任务A,它要等待其他4个任务执行完毕之后才能执行,此时就可以利用CountDownLatch来实现这种功能了。

  CountDownLatch让一些线程阻塞知道另一些线程完成一系列操作后才被唤醒,CountDownLatch主要有两个方法,当一份或多个线程调用await方法时,调用线程会被阻塞。其他线程调用countDown方法会将计数器减1(调用countDown方法的线程不会阻塞),当计数器的值变为0时,因调用await方法被阻塞的线程会被唤醒,继续执行。

public class CountDownLatchDemo {

    public static void main(String[] args) {
        CountDownLatch countDownLatch = new CountDownLatch(6);
        for (int i = 0; i < 6; i++) {
            new Thread(()->{
                System.out.println("当前线程任务结束 : " + Thread.currentThread().getName());
                countDownLatch.countDown();
            }, String.valueOf(i)).start();
        }

        try {
            // 等待其他线程执行完再执行
            countDownLatch.await();
            System.out.println("************全部执行结束***********");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

输出结果:

当前线程任务结束 : 0
当前线程任务结束 : 2
当前线程任务结束 : 3
当前线程任务结束 : 1
当前线程任务结束 : 4
当前线程任务结束 : 5
************全部执行结束***********

二、CyclicBarrier

CyclicBarrier的字面意思是可循环(Cyclic)使用的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活,线程进入屏障通过CyclicBarrier的await()方法,当调用await()方法之后,线程就处于barrier了。

代码测试:收集七颗龙珠,召唤神龙。

public class CyclicBarrierDemo {

    public static void main(String[] args) {
        CyclicBarrier barrier = new CyclicBarrier(7,
                () -> {
                    System.out.println("**********召唤神龙**********");
                });
        for (int i = 1; i <= 7; i++){
            new Thread(()->{
               System.out.println("第" + Thread.currentThread().getName() + " 颗龙珠被收集");
                try {
                    barrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }, String.valueOf(i)).start();
        }
    }
}

输出结果:

第1 颗龙珠被收集
第7 颗龙珠被收集
第6 颗龙珠被收集
第5 颗龙珠被收集
第4 颗龙珠被收集
第3 颗龙珠被收集
第2 颗龙珠被收集
**********召唤神龙**********

三、Semaphore

Semaphore翻译成字面意思为信号量,Semaphore可以控同时访问的线程个数,通过 acquire() 获取一个许可,如果没有就等待,而 release() 释放一个许可。

信号量主要用于两个目的,一个是用于多个共享资源的互斥使用,另一个是用于并发线程数的控制

代码实现小案例:6辆汽车抢夺3个停车位。

public class SemaphoreDemo {

    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(3);

        for (int i = 1; i <= 6; i++){
            new Thread(()->{
                try {
                    // 获取资源
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + "号车获得停车位");
                    TimeUnit.SECONDS.sleep(3);
                    System.out.println(Thread.currentThread().getName() + "号车停车3秒离开停车位");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    // 释放资源
                    semaphore.release();
                }

            },String.valueOf(i)).start();
        }
    }
}

输出结果:

1号车获得停车位
3号车获得停车位
4号车获得停车位
4号车停车3秒离开停车位
3号车停车3秒离开停车位
5号车获得停车位
1号车停车3秒离开停车位
6号车获得停车位
2号车获得停车位
6号车停车3秒离开停车位
5号车停车3秒离开停车位
2号车停车3秒离开停车位

Process finished with exit code 0
原文地址:https://www.cnblogs.com/ch-forever/p/10782270.html