常用的辅助类
文章目录
- 常用的辅助类
- 1. 同步工具类
- 1.1 CountDownLatch
- 概念
- 方法
- 案例
- 1.2 CyclicBarrier
- 概述
- 构造器
- 方法
- 案例
- 1.3 两者的比较
- 2 Semaphore
- 2.1 概念
- 2.2 常用方法
- 2.3 案例
JUC并发包下有四个并发工具类,闭锁CountDownlatch、栅栏CyclicBarrier、信号量Semaphore、交换器Exchanger。 本篇文章我们对前三个辅助类进行讲解。
1. 同步工具类
1.1 CountDownLatch
概念
- CountDownLatch允许一个或者多个线程去等待其他线程完成操作。
- CountDownLatch接收一个
int
型参数,表示要等待的工作线程的个数
方法
-
await()
:使当前线程进入同步队列进行等待,直到 latch 的值被减到0或者当前线程被中断,当前线程就会被唤醒。 -
await(long timeout, TimeUnit unit)
:带超时时间的await()。 -
countDown()
:使 latch 的值减1,如果减到了0,则会唤醒所有等待在这个 latch 上的线程。 -
getCount()
:获得latch的数值。
案例
//模拟放学锁门,只有六个同学全部走了,老师才可以锁门
public class CountDownLatchTest {
public static void main(String[] args) throws InterruptedException {
//总数为6
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 1; i <= 6; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName() + "离开了教室");
countDownLatch.countDown();//计数器-1
},String.valueOf(i)).start();
}
//等待计数器归0再向下执行
countDownLatch.await();
System.out.println("关门了!");
}
}
1.2 CyclicBarrier
概述
- CyclicBarrier:循环屏障,可以给离散的任务添加逻辑层次。
- 各个线程会互相等待,直到所有线程都完成了,再一起突破屏障。如上课时,只有所有学生都到了,老师才会上课。
构造器
- CyclicBarrier有两个构造器
- CyclicBarrier(int parties) :创建一个CyclicBarrier对象,并指定其parties
- CyclicBarrier(int parties, Runnable barrierAction) :指定parties,并且执行其callBack(在所有线程都到达时执行此barrierAction)
- parties:当前CyclicBarrier管理的线程的个数
方法
await()
:等待所有 parties 已经在这个障碍上调用了await。如果当前线程不是最后一个线程,那么它被禁用以进行线程调度,并且处于休眠状态,直到发生下列事情之一:
- 最后一个线程到达
- 其他一些线程中断当前线程
- 其他一些线程中断了其他等待线程中的一个
- 其他一些线程在等待屏障时超时
- 其他一些线程在这个屏障上调用 reset()
await(long timeout, TimeUnit unit)
:等待所有 parties已经在此屏障上调用 await ,或指定的等待时间过去。getNumberWaiting()
:返回目前正在等待障碍的各方的数量。getParties()
:返回突破障碍所需的数量isBroken()
:查询这个障碍是否处于破碎状态。reset()
:将屏障重置为初始状态。
案例
//模拟考试交卷,只有等到全部人交卷了,才可以走
public class CyclicBarrierTest {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(6,()->{
System.out.println(“考试结束,大家可以走了”);
});
for (int i = 1; i <= 6; i++) {
int temp = i;
new Thread(()->{
System.out.println(Thread.currentThread().getName() + "交卷,老师收了学生" + temp + "的试卷");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
},"学生" + i).start();
}
}
1.3 两者的比较
CountDownLatch | CyclicBarrier | |
软件包 | java.util.concurrent | java.util.concurrent |
适用情景 |
|
|
等待结束 | 各线程之间不再互相影响,可以继续做自己的事情。不再执行下一个目标工作 | 在屏障点达到后,允许所有线程继续执行,达到下一个目标。可以重复使用CyclicBarrier |
异常 | 如果其中一个线程由于中断,错误,或超时导致永久离开屏障点,其他线程也将抛出异常。 | |
其他 | 如果BarrierAction不依赖于任何Party中的所有线程,那么在任何party中的一个线程被释放的时候,可以直接运行这个Action。 |
2 Semaphore
2.1 概念
- Semaphore通常我们叫它信号量, 可以用来控制同时访问特定资源的线程数量,通过协调各个线程,以保证合理的使用资源。
- 作用:多个共享资源互斥的使用,并发限流,控制最大的线程数。
2.2 常用方法
acquire()
:获取一个令牌,在获取到令牌、或者被其他线程调用中断之前线程一直处于阻塞状态。acquire(int permits)
:获取一个令牌,在获取到令牌、或者被其他线程调用中断、或超时之前线程一直处于阻塞状acquireUninterruptibly()
:获取一个令牌,在获取到令牌之前线程一直处于阻塞状态(忽略中断)。tryAcquire()
:尝试获得令牌,返回获取令牌成功或失败,不阻塞线程。tryAcquire(long timeout, TimeUnit unit)
:尝试获得令牌,在超时时间内循环尝试获取,直到尝试获取成功或超时返回,不阻塞线程。release()
:释放一个令牌,唤醒一个获取令牌不成功的阻塞线程。hasQueuedThreads()
:等待队列里是否还存在等待线程。getQueueLength()
:获取等待队列里阻塞的线程数。drainPermits()
:清空令牌把可用令牌数置为0,返回清空令牌的数量。availablePermits()
:返回可用的令牌数量。
2.3 案例
//模拟抢车位,只有三个车位,六辆车
public class SemaphoreTest {
public static void main(String[] args) {
//线程数量-三个车位
Semaphore semaphore = new Semaphore(3);
for (int i = 1; i <= 6; i++) {
new Thread(()->{
try {
semaphore.acquire();//acquire()得到,即抢到车位
System.out.println(Thread.currentThread().getName() + "抢到车位");
TimeUnit.SECONDS.sleep(2);//模拟停车时间为2s
System.out.println(Thread.currentThread().getName() + "离开车位");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
semaphore.release();//release()释放,即离开车位
}
}).start();
}
}
}