天天看点

java JUC 的CountDownLatch,Semaphore,CyclicBarrier的使用起源CountDownLatch的使用CyclicBarrier的使用Semaphore的使用

java JUC 的CountDownLatch,Semaphore,CyclicBarrier

  • 起源
  • CountDownLatch的使用
  • CyclicBarrier的使用
  • Semaphore的使用

起源

一直都只了解过countdownlatch,近期在看redission 实现分布式锁的实现的时候发现了Semaphore。

CountDownLatch的使用

countDownLatch可以作为计数器使用,比如支付,支付需要同时调用很多三方服务,我们为了提升接口的速度,使用多线程同时去获取库存,订单,余额等信息,全部执行完成后再调用真正的下单接口。

执行顺序: 主线程 -》子线程 -》主线程

CountDownLatch 使一个线程A或是组线程A等待其它线程执行完毕后,一个线程A或是组线程A才继续执行
           
package com.example.springbootmbplus.demo;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @ClassName: CountDownLatchDemo
 * @Description: CountDownLatch demo
 * @author: godShan
 * @Date: 2020/6/15 16:29
 */
public class CountDownLatchDemo {

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        //老板等待员工完成工作,开始检查任务
        //老板手下有5个员工
        CountDownLatch countDownLatch = new CountDownLatch(5);

        for (int i = 0; i < 5; i++) {
            System.out.println("老板给员工" + (i + 1) + "分配任务");
            executorService.execute(new Worker(countDownLatch));
        }

        //老板等待通知开始检查
        countDownLatch.await();
        executorService.shutdown();
        //老板开始检查工作
        System.out.println("老板开始检查工作");
    }

    /**
     * 员工
     */
    static class Worker implements Runnable {

        private CountDownLatch countDownLatch;

        public Worker(CountDownLatch countDownLatch) {
            this.countDownLatch = countDownLatch;
        }

        @Override
        public void run() {
            System.out.println("员工开始工作 ----------------------");
            countDownLatch.countDown();
            System.out.println("员工完成工作 ----------------------");
        }
    }
}

           

输出结果:

老板给员工1分配任务

老板给员工2分配任务

老板给员工3分配任务

老板给员工4分配任务

老板给员工5分配任务

员工开始工作 ----------------------

员工开始工作 ----------------------

员工完成工作 ----------------------

员工完成工作 ----------------------

员工开始工作 ----------------------

员工完成工作 ----------------------

员工开始工作 ----------------------

员工完成工作 ----------------------

员工开始工作 ----------------------

员工完成工作 ----------------------

老板开始检查工作

CyclicBarrier的使用

CyclicBarrier主要用来做计数,但是它和CountDownLatch不同。它是通过await方法阻塞子线程,等所有的子线程数量到达后,执行回调任务后子线程再去执行await 之后的代码逻辑。

执行顺序: 主线程 -》子线程 -》主线程的回调任务 -》子线程await阻塞后的代码逻辑

CyclicBarrier:一组线程使用await()指定barrier,所有线程都到达各自的barrier后,再同时执行各自barrier下面的代码
           
package com.example.springbootmbplus.demo;

import lombok.SneakyThrows;

import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @ClassName: CyclicBarrierDemo
 * @Description: cyclicBarrier demo
 * @author: godShan
 * @Date: 2020/6/15 15:33
 */
public class CyclicBarrierDemo2 {

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        //老板等待员工完成工作,开始检查任务
        //老板手下有5个员工
        CyclicBarrier cyclicBarrier = new CyclicBarrier(5, () -> {
            //老板等待通知开始检查
            //老板开始检查工作
            System.out.println("老板开始检查工作");
        });

        for (int i = 0; i < 5; i++) {
            System.out.println("老板给员工" + (i + 1) + "分配任务");
            executorService.execute(new Worker(cyclicBarrier));
        }

        executorService.shutdown();

    }

    /**
     * 员工
     */
    static class Worker implements Runnable {

        private CyclicBarrier cyclicBarrier;

        public Worker(CyclicBarrier cyclicBarrier) {
            this.cyclicBarrier = cyclicBarrier;
        }

        @SneakyThrows
        @Override
        public void run() {
            System.out.println("员工开始工作 ----------------------");
            cyclicBarrier.await();
            System.out.println("员工完成工作 ----------------------");
        }
    }

}

           

输出结果:

老板给员工1分配任务

老板给员工2分配任务

老板给员工3分配任务

老板给员工4分配任务

老板给员工5分配任务

员工开始工作 ----------------------

员工开始工作 ----------------------

员工开始工作 ----------------------

员工开始工作 ----------------------

员工开始工作 ----------------------

老板开始检查工作

员工完成工作 ----------------------

员工完成工作 ----------------------

员工完成工作 ----------------------

员工完成工作 ----------------------

员工完成工作 ----------------------

可以看到 CountDownLatch和CyclicBarrier的区别

1.CountDownLatch的countDown不会去阻塞线程;CyclicBarrier调用await会阻塞线程直到回调的方法执行完成

2.CountDownLatch当计数到0时,计数无法被重置;CyclicBarrier计数达到指定值时,计数置为0重新开始

Semaphore的使用

Semaphore主要是用来做限流的。

Semaphore是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源
           
package com.example.springbootmbplus.demo;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @ClassName: SamphoreDemo
 * @Description: SemaphoreDemo
 * @author: godShan
 * @Date: 2020/6/15 14:37
 */
public class SemaphoreDemo {

    public static void main(String[] args) throws InterruptedException {
        ThreadLocalRandom random = ThreadLocalRandom.current();
        ExecutorService executorService = Executors.newCachedThreadPool();
        //模拟停车位 100个
        Semaphore semaphore = new Semaphore(100);
        //模拟需要停车的数量
        AtomicInteger needSum = new AtomicInteger(0);
        for (int i = 0; i < 2000; i++) {
            TimeUnit.SECONDS.sleep(random.nextInt(0,5));
            System.out.println("第【" + (i + 1) + "】辆车来到停车场入口");
            executorService.execute(() -> {
                try {
                    //占用停车位,内部100-1,如果数量不够了着堵塞
                    semaphore.acquire();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //总共停车数
                needSum.getAndAdd(1);
                System.out.println("今日第【" + needSum.get() + "】进入停车场");
                System.out.println("停车场剩余车位: 【" + (semaphore.availablePermits()) + "】");
                //todo do something
                try {
                    //模拟逻辑停车时间 5-100秒

                    TimeUnit.SECONDS.sleep(random.nextInt(50,500));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //离开停车场
                semaphore.release();
                System.out.println("有一辆车离开停车场!");
                System.out.println("停车场剩余车位: 【" + (semaphore.availablePermits()) + "】");
            });
        }

        executorService.shutdown();
    }

}