原理
基于 AQS 实现.
让需要的暂时阻塞的线程, 进入一个死循环里面, 得到某个条件后再退出循环, 以此实现阻塞当前线程的效果.
CountDownLatch
CountDownLatch 一般用于某个线程 A 等待若干个其他线程执行完任务之后, 它才执行;
CountDownLatch 是不能够重用的
利用它可以实现类似计数器的功能. 比如有一个任务 A, 它要等待其他 4 个任务执行完毕之后才能执行, 此时就可以利用 CountDownLatch 来实现这种功能了.
CountDownLatch 类只提供了一个构造器:
public CountDownLatch(int count) { }; // 参数 count 为计数值
然后下面这 3 个方法是 CountDownLatch 类中最重要的方法:
- public void await() throws InterruptedException { }; // 调用 await() 方法的线程会被挂起, 它会等待直到 count 值为 0 才继续执行
- public boolean await(long timeout, TimeUnit unit) throws InterruptedException { }; // 和 await() 类似, 只不过等待一定的时间后 count 值还没变为 0 的话就会继续执行
- public void countDown() { }; // 将 count 值减 1
- public class Test {
- public static void main(String[] args) {
- final CountDownLatch latch = new CountDownLatch(2);
- new Thread(){
- 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();
- }
- };
- }.start();
- new Thread(){
- 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();
- }
- };
- }.start();
- try {
- System.out.println("等待 2 个子线程执行完毕...");
- latch.await();
- System.out.println("2 个子线程已经执行完毕");
- System.out.println("继续执行主线程");
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- // 执行结果
线程 Thread-0 正在执行
线程 Thread-1 正在执行
等待 2 个子线程执行完毕...
线程 Thread-0 执行完毕
线程 Thread-1 执行完毕
2 个子线程已经执行完毕
继续执行主线程
CyclicBarrier
而 CyclicBarrier 一般用于一组线程互相等待至某个状态, 然后这一组线程再同时执行;
而 CyclicBarrier 是可以重用的
CyclicBarrier 提供 2 个构造器:
- public CyclicBarrier(int parties, Runnable barrierAction) {
- }
- public CyclicBarrier(int parties) {
- }
参数 parties 指让多少个线程或者任务等待至 barrier 状态; 参数 barrierAction 为当这些线程都达到 barrier 状态时会执行的内容.
然后 CyclicBarrier 中最重要的方法就是 await 方法, 它有 2 个重载版本:
- public int await() throws InterruptedException, BrokenBarrierException {
- };
- public int await(long timeout, TimeUnit unit)throws InterruptedException,BrokenBarrierException,TimeoutException {
- };
第一个版本比较常用, 用来挂起当前线程, 直至所有线程都到达 barrier 状态再同时执行后续任务;
第二个版本是让这些线程等待至一定的时间, 如果还有线程没有到达 barrier 状态就直接让到达 barrier 的线程执行后续任务.
假若有若干个线程都要进行写数据操作, 并且只有所有线程都完成写数据操作之后, 这些线程才能继续做后面的事情, 此时就可以利用 CyclicBarrier 了:
- public class Test {
- public static void main(String[] args) {
- int N = 4;
- CyclicBarrier barrier = new CyclicBarrier(N);
- for(int i=0;i<N;i++)
- new Writer(barrier).start();
- }
- static class Writer extends Thread{
- private CyclicBarrier cyclicBarrier;
- public Writer(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-3 正在写入数据...
线程 Thread-2 正在写入数据...
线程 Thread-1 正在写入数据...
线程 Thread-2 写入数据完毕, 等待其他线程写入完毕
线程 Thread-0 写入数据完毕, 等待其他线程写入完毕
线程 Thread-3 写入数据完毕, 等待其他线程写入完毕
线程 Thread-1 写入数据完毕, 等待其他线程写入完毕
所有线程写入完毕, 继续处理其他任务...
所有线程写入完毕, 继续处理其他任务...
所有线程写入完毕, 继续处理其他任务...
所有线程写入完毕, 继续处理其他任务...
Semaphore
Semaphore 其实和锁有点类似, 它一般用于控制对某组资源的访问权限.
Semaphore 翻译成字面意思为 信号量, Semaphore 可以控同时访问的线程个数, 通过 acquire() 获取一个许可, 如果没有就等待, 而 release() 释放一个许可.
假若一个工厂有 5 台机器, 但是有 8 个工人, 一台机器同时只能被一个工人使用, 只有使用完了, 其他工人才能继续使用. 那么我们就可以通过 Semaphore 来实现:
- public class Test {
- public static void main(String[] args) {
- int N = 8; // 工人数
- Semaphore semaphore = new Semaphore(5); // 机器数目
- for(int i=0;i<N;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();
- }
- }
- }
- }
来源: http://www.bubuko.com/infodetail-2949329.html