CountDownLatch、Semaphore、CyclicBarrier

摘要
CountDownLatch、Semaphore和CyclicBarrier都是用于同步一批线程的行为


CountDownLatch
是一个计数器闭锁,同时只能有一个线程去操作该计数器,通过它可以完成类似于阻塞当前线程的功能。
方法说明:

  • await()
    线程会一直处于阻塞状态,当计数器值减至零时,所有因调用await()方法而处于等待状态的线程就会继续往下执行
  • countDown()
    计数器减一。这种现象只会出现一次,因为计数器不能被重置,如果业务上需要一个可以重置计数次数的版本,可以考虑使用CycliBarrier
    通过CountDownLatch 可以模拟并发场景
static int THREAD_NUM=1000;
static CountDownLatch countDownLatch=new CountDownLatch(THREAD_NUM);
for(int i=0;i<THREAD_NUM;i++){
    final int id=i;
    Thread thread=new Thread(new Runnable() {
        @Override
        public void run() {
            try{
                countDownLatch.await();
                //每次请求都直接通过service获取数据
                ReqMerger reqMerger =reqMergerService.queryById(id);
            }catch (Exception ex){
                System.out.println(ex.getMessage());
            }
        }
    });
    thread.start();
    countDownLatch.countDown();
}

Semaphore
Semaphore的值被获取到后是可以释放的,不像CountDownLatch那样一直减到底。它也被更多地用来限制流量,类似阀门的功能。如果限定某些资源最多有N个线程可以访问,那么超过N个就不允许再有线程来访问,同时当现有线程结束后,就会释放,然后允许新的线程进来。有点类似于锁的lock与 unlock过程。
方法说明:

  • acquire()
    用于获取权限,其底层实现与CountDownLatch.countdown()类似
  • release()
    用于释放权限
private final static int threadCount = 20;
static ExecutorService exec = Executors.newCachedThreadPool();
public static void main(String[] args){
    // 每次最多三个线程获取许可
    final Semaphore semaphore = new Semaphore(3);
    for (int i = 0; i < threadCount; i++) {
        final int threadNum = i;
        exec.execute(() -> {
            try {
                // 获取一个许可
                semaphore.acquire();
                test(threadNum);
                // 释放一个许可
                semaphore.release();
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        });
    }
    exec.shutdown();
}
private static void test(int threadNum) throws Exception {
    System.out.println(threadNum);
    Thread.sleep(1000);
}

CyclicBarrier
允许一组线程相互等待,直到到达某个公共屏障点。通过它可以完成多个线程之间相互等待,只有当每个线程都准备就绪后,才能各自继续往下执行后面的操作。当某个线程调用await方法时,该线程进入等待状态,且计数器加1,当计数器的值达到设置的初始值时,所有因调用await进入等待状态的线程被唤醒,继续执行后续操作。因为CycliBarrier在释放等待线程后可以重用,所以称为循环barrier。CycliBarrier支持一个可选的Runnable,在计数器的值到达设定值后(但在释放所有线程之前),该Runnable运行一次,注,Runnable在每个屏障点只运行一个。

private static CyclicBarrier barrier = new CyclicBarrier(5);
static ExecutorService executor = Executors.newCachedThreadPool();
public static void main(String[] args) throws Exception {
    for (int i = 0; i < 10; i++) {
        final int threadNum = i;
        Thread.sleep(1000);
        executor.execute(() -> {
            try {
                test(threadNum);
            } catch (Exception e) {
                System.out.println(e);
            }
        });
    }
    executor.shutdown();
}

private static void test(int threadNum) throws Exception {
    Thread.sleep(1000);
    System.out.println(threadNum+" is ready");
    barrier.await();
    System.out.println(threadNum+" is continue");
}

运行结果

0 is ready
1 is ready
2 is ready
3 is ready
4 is ready
4 is continue
1 is continue
0 is continue
3 is continue
2 is continue
5 is ready
6 is ready
7 is ready
8 is ready
9 is ready
5 is continue
9 is continue
6 is continue
7 is continue
8 is continue
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值