CountDownLatch
描述:
一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
API简述
// 构造器, 指定计数值的初始值
public CountDownLatch(int count)
// 使当前线程等待, 除非当前计数为0
public void await()
// 线程等待, 添加了个超时时间,如果超过了 设置的时间 及时计数不为0也继续执行
public boolean await(long timeout, TimeUnit unit)
// 计数减一
public void countDown()
应用
// 创建一个默认计数为1 的countDownLatch
final CountDownLatch countDownLatch = new CountDownLatch(1);
new Thread(() -> {
try {
// 线程等待 countDownLatch计数为0
countDownLatch.await();
System.out.println(Thread.currentThread().getName() + " 在执行 countDownLatch.await();");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
try {
System.out.println(Thread.currentThread().getName() + " 在执行 countDownLatch.countDown();");
TimeUnit.SECONDS.sleep(1);
// 计数减一
countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
CyclicBarrier
和CountDownLatch 作用类似,不过他可以循环使用,相当于一个阀门,如果等待的线程数到达这个阈值则放行所有等待的线程, 然后从新计算
官方解释:允许一组线程全部等待彼此达到共同屏障点的同步辅助
countdownLatch是计数为0 后放行所有等待的线程,CyclicBarrier是等待的线程数到达指定的值后放行所有等待的线程
API
// 构造器, parties 线程等待数阈值
public CyclicBarrier(int parties)
// 构造器,parties 线程等待数阈值, barrierAction 当屏障数到达阈值后执行的回调函数
public CyclicBarrier(int parties, Runnable barrierAction)
// await() 线程等待
public int await() throws InterruptedException, BrokenBarrierException
// 带有等待超时时间的await
public int await(long timeout, TimeUnit unit)
// 重置阈值从新计算, 如果有线程在等待则抛异常java.util.concurrent.BrokenBarrierException
public void reset()
应用
// 当等待的线程数到达设置的阈值的时候,执行回调函数,然后等待的线程继续执行
final CyclicBarrier cyclicBarrier = new CyclicBarrier(2,
new Thread(()-> {
System.out.println("执行回调函数。。。");
}));
new Thread(() -> {
try {
// 线程第一次等待
cyclicBarrier.await();
System.out.println(Thread.currentThread().getName() +" 开始执行1");
// 线程第二次等待
cyclicBarrier.await();
System.out.println(Thread.currentThread().getName() +" 开始执行2");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
try {
cyclicBarrier.await();
System.out.println(Thread.currentThread().getName() +" 开始执行1!");
cyclicBarrier.await();
System.out.println(Thread.currentThread().getName() +" 开始执行2!");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
输出结果
执行回调函数。。。
Thread-2 开始执行1!
Thread-1 开始执行1
执行回调函数。。。
Thread-1 开始执行2
Thread-2 开始执行2!
Semaphore
字面意思就是信号量,可以控制并发访问的线程数;Semaphore可以用于做流量控制
API
// 创建一个指定数量许可的Semaphore
public Semaphore(int permits)
// fair 是否公平
public Semaphore(int permits, boolean fair)
// 获取一个许可, 如果获取不到则阻塞
public void acquire() throws InterruptedException
// 尝试获取一个许可,获取到返回true, 获取不到返回false
public boolean tryAcquire()
// 在指定时间内尝试获取一个许可
public boolean tryAcquire(long timeout, TimeUnit unit)
// 释放一个许可
public void release()
//释放多个许可
public void release(int permits)
//返回此信号量中可用的许可证的当前数量。
public int availablePermits()
//获取并返回所有可用的许可, 此方法会消耗掉所有的可用许可
public int drainPermits()
运用
// 创建一个有两个许可证的Semaphore
final Semaphore semaphore = new Semaphore(2);
System.out.println("默认有" + semaphore.availablePermits() + " 个许可");
// 创建10 个线程执行
for (int i = 0; i <10 ; i++) {
new Thread(() -> {
try {
// 获取一个许可
Stopwatch stopwatch = Stopwatch.createStarted();
semaphore.acquire();
TimeUnit.SECONDS.sleep(1);
System.out.println(stopwatch.elapsed(TimeUnit.SECONDS) +" == " + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 释放一个许可
semaphore.release();
}
}).start();
}
输出结果, 每秒只有2个线程在执行
默认有2 个许可
1 == Thread-1
1 == Thread-9
2 == Thread-8
2 == Thread-5
3 == Thread-0
3 == Thread-6
4 == Thread-3
4 == Thread-2
5 == Thread-7
5 == Thread-4