版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/byhook/article/details/81301734
概述
同步屏障指的是:
让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。
CyclicBarrier
CyclicBarrier的字面意思是可循环使用(Cyclic)的屏障(Barrier)
。
以一个实例来说明:
public class Solution {
public static void main(String[] args) {
int count = 4;
CyclicBarrier barrier = new CyclicBarrier(count);
for (int i = 0; i < count; i++) {
new Worker(barrier).start();
}
}
public static class Worker extends Thread {
private CyclicBarrier cyclicBarrier;
public Worker(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
System.out.println("线程 " + Thread.currentThread().getName() + "正在执行");
try {
//以睡眠来模拟写入数据操作
Thread.sleep(5000);
System.out.println("线程 " + Thread.currentThread().getName() + "执行完毕");
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("所有线程执行完毕");
}
}
}
输出:
线程 Thread-0正在执行
线程 Thread-1正在执行
线程 Thread-2正在执行
线程 Thread-3正在执行
线程 Thread-0执行完毕
线程 Thread-2执行完毕
线程 Thread-1执行完毕
线程 Thread-3执行完毕
所有线程执行完毕
所有线程执行完毕
所有线程执行完毕
所有线程执行完毕
内部基于ReentrantLock实现
。
CountDownLatch
CountDownLatch
的计数器只能使用一次,而CyclicBarrier的计数器可以使用
reset()方法重置。所以
CyclicBarrier`能处理更为复杂的业务场景。例如,如果计算发生错误,可以重置计数器,并让线程重新执行一次。
public class Solution {
public static void main(String[] args) {
final CountDownLatch latch = new CountDownLatch(2);
new Thread(new WorkRunnable(latch)).start();
new Thread(new WorkRunnable(latch)).start();
try {
System.out.println("等待2个子线程执行完毕...");
latch.await();
System.out.println("2个子线程已经执行完毕");
System.out.println("继续执行主线程");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static class WorkRunnable implements Runnable {
private CountDownLatch latch;
public WorkRunnable(CountDownLatch countDownLatch) {
this.latch = countDownLatch;
}
@Override
public void run() {
try {
System.out.println("子线程 " + Thread.currentThread().getName() + "正在执行");
Thread.sleep(3000);
System.out.println("子线程 " + Thread.currentThread().getName() + "执行完毕");
latch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
输出:
子线程 Thread-0正在执行
等待2个子线程执行完毕...
子线程 Thread-1正在执行
子线程 Thread-0执行完毕
子线程 Thread-1执行完毕
2个子线程已经执行完毕
继续执行主线程
内部基于AQS
实现的非公平锁。
Semaphore
Semaphore(信号量)是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源。
假设有6个人在高铁站,排队取票,只有三台机器,可以如下实现:
public class Solution {
public static void main(String[] args) {
int count = 6; //取票人数
Semaphore semaphore = new Semaphore(3); //取票机器数目
for (int i = 0; i < count; i++)
new Worker(i, semaphore).start();
}
static class Worker extends Thread {
private int num;
private Semaphore semaphore;
public Worker(int num, Semaphore semaphore) {
this.num = num;
this.semaphore = semaphore;
}
@Override
public void run() {
try {
semaphore.acquire();
System.out.println("第" + this.num + "个人正在取票...");
Thread.sleep(2000);
System.out.println("第" + this.num + "个人取票完成");
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
输出:
扫描二维码关注公众号,回复:
5403940 查看本文章
第0个人正在取票...
第1个人正在取票...
第2个人正在取票...
第0个人取票完成
第1个人取票完成
第3个人正在取票...
第4个人正在取票...
第2个人取票完成
第5个人正在取票...
第3个人取票完成
第4个人取票完成
第5个人取票完成
小结
CountDownLatch和CyclicBarrier
都能够实现线程之间的等待,只不过它们侧重点不同:
CountDownLatch
一般用于某个线程A等待若干个其他线程执行完任务之后,它才执行,不支持重用。
CyclicBarrier
一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行,支持重用。
Semaphore
其实和锁机制有点类似,它一般用于控制对某组资源的访问权限。
参考
《Java并发编程的艺术》
https://www.cnblogs.com/dolphin0520/p/3920397.html