前言
Java JUI之并发编程,CountDownLatch和Semaphone的应用
1、CountDownLatch
CountDownLatch是一个同步工具类,它通过一个计数器来实现的,初始值为线程的数量。每当一个线程完成了自己的任务,计数器的值就相应得减1。当计数器到达0时,表示所有的线程都已执行完毕,然后在等待的线程就可以恢复执行任务。
CountDownLatch(int count):count为计数器的初始值(一般需要多少个线程执行,count就设为几)。
- CountDownLatch(int count):count为计数器的初始值(一般需要多少个线程执行,count就设为几)。
- countDown(): 每调用一次计数器值-1,直到count被减为0,代表所有线程全部执行完毕。
- getCount():获取当前计数器的值。
- await(): 等待计数器变为0,即等待所有异步线程执行完毕。
- boolean await(long timeout, TimeUnit unit):
此方法与await()区别:
①此方法至多会等待指定的时间,超时后会自动唤醒,若 timeout 小于等于零,则不会等待
②boolean 类型返回值:若计数器变为零了,则返回 true;若指定的等待时间过去了,则返回 false
1.1、应用场景
- 某个线程需要在其他n个线程执行完毕后再向下执行
- 多个线程并行执行同一个任务,提高响应速度
列子:
import lombok.extern.slf4j.Slf4j; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @Slf4j public class ThreadTest extends Thread{ public static void main(String[] args) throws InterruptedException, ExecutionException { /*ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 2, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(5), new ThreadPoolExecutor.AbortPolicy());*/ ExecutorService executorService = Executors.newWorkStealingPool(); //定义一个计数器 CountDownLatch countDownLatch = new CountDownLatch(20); //把各个地区统计数据放到一个map里面,key:区域 value:销量 、 统计用的时间 for (int i = 0; i < 20; i++) { Runnable runnable = new Runnable() { @Override public void run() { //销量统计的方法 countDownLatch.countDown(); } }; executorService.execute(runnable); } //等待形成全部执行完成 countDownLatch.await(); //把map打印出来 log.info("end ----"); } }
2、Semaphone
一个计数信号量,从概念上将,信号量维护了一个许可集,如有必要,在许可可用前会阻塞每一个acquire(),然后在获取该许可。每个release()添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,Semaphore只对可用许可的号码进行计数,并采取相应的行动
具体常用的方法有:
方法 | 说明 |
acquire() | 从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断 |
release() | 释放一个许可,将其返回给信号量 |
设置许可数量,Semaphore semaphore = new Semaphore(3);
一般acquire()都会抛出异常,release在finally中执行
例子:
汽车抢位
public static void main(String[] args) { /** * 10辆车 4个停车位的问题 */ //初始化信号量 Semaphore semaphore = new Semaphore(4); ExecutorService executorService = Executors.newFixedThreadPool(100); for (int i = 0; i < 10; i++) { Runnable runnable = new Runnable() { @Override public void run() { try { //获取许可 semaphore.acquire(); System.out.println("进入车位....."); TimeUnit.SECONDS.sleep((int) (Math.random() * 10)); System.out.println("离开车位....."); } catch (InterruptedException e) { e.printStackTrace(); } finally { //释放许可 semaphore.release(); } } }; executorService.execute(runnable); } }