作用: 限流
一、Semaphore 作用:限制访问资源的线程数量
创建
构造器 | 参数 |
---|---|
Semaphore(int n) | n:信号量 |
Semaphore(int n,boolean p) | n:信号量,p:是否公平 |
使用
//创建信号量为2的Semaphore,可同时让两个线程访问
Semaphore semaphore = new Semaphore(2);
//获取信号,信号量-1,
semaphore.acquire();
/** 代码逻辑 **/
//释放信号,信号量+1,释放信号
semaphore.release();
若超过信号量2,其他线程进入队列等待
二、CyclicBarrier
作用: 访问线程达到指定数量时,执行await之后的代码
使用
CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
for (int i = 0; i < 10; i++) {
new Thread(()->{
try {
System.out.println("等待");
cyclicBarrier.await();
//代码逻辑
System.out.println("执行任务完毕");
} catch (Exception e) {
throw new RuntimeException(e);
}
}).start();
}
注意:
线程数没有达到指定数量时,await会一直等待。
若需要限时且不想一直等待,可以使用cyclicBarrier.await(时间,时间单位),这样超时就会抛异常
三、CountdownLatch
作用:当计数器达到0时,执行await之后的代码
CountdownLatch可以实现CyclicBarrier的功能(正常不会这样用的,因为已经有CyclicBarrier了)
CountDownLatch countdownLatch = new CountDownLatch(5);
for (int i = 0; i < 5; i++) {
new Thread(()->{
try {
//count减1
countdownLatch.countDown();
//等待计数为0
countdownLatch.await();
System.out.println("执行任务");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}).start();
}
CountdownLatch与CyclicBarrier的区别:
CountdownLatch是一次性的 , 而CyclicBarrier可调用reset重复使用,
最大的区别是CountdownLatch还可以实现N个任务线程await等待其他线程完成countDown后,继续执行任务线程。
例子
以下是3个任务线程 等待5个线程完成countDown后,继续执行3个任务线程。
CountDownLatch countdownLatch = new CountDownLatch(5);
//5个执行A任务的线程
for (int i = 0; i < 5; i++) {
new Thread(()->{
//代码逻辑
System.out.println("A任务逻辑");
countdownLatch.countDown();
}).start();
}
//3个执行B任务的线程
for (int i = 0; i < 3; i++) {
new Thread(()->{
try {
//等待A任务完成
countdownLatch.await();
System.out.println("B任务逻辑");
//代码逻辑
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}).start();
}
注意:
计数器不为0,await会一直等待。
若需要限时且不想一直等待,可以使用cyclicBarrier.await(时间 , 时间单位 ),这样超时就会抛异常
底层实现
AQS( Abstract Queued Synchronizer )