一、CountDownLatch
CountDownLatch类位于java.util.concurrent包下,利用它可以实现类似计数器的功能。
比如有一个任务A,它要等待其他4个任务执行完毕之后才能执行,此时就可以利用CountDownLatch来实现这种功能了。
CountDownLatch让一些线程阻塞知道另一些线程完成一系列操作后才被唤醒,CountDownLatch主要有两个方法,当一份或多个线程调用await方法时,调用线程会被阻塞。其他线程调用countDown方法会将计数器减1(调用countDown方法的线程不会阻塞),当计数器的值变为0时,因调用await方法被阻塞的线程会被唤醒,继续执行。
public class CountDownLatchDemo { public static void main(String[] args) { CountDownLatch countDownLatch = new CountDownLatch(6); for (int i = 0; i < 6; i++) { new Thread(()->{ System.out.println("当前线程任务结束 : " + Thread.currentThread().getName()); countDownLatch.countDown(); }, String.valueOf(i)).start(); } try { // 等待其他线程执行完再执行 countDownLatch.await(); System.out.println("************全部执行结束***********"); } catch (InterruptedException e) { e.printStackTrace(); } } }
输出结果:
当前线程任务结束 : 0 当前线程任务结束 : 2 当前线程任务结束 : 3 当前线程任务结束 : 1 当前线程任务结束 : 4 当前线程任务结束 : 5 ************全部执行结束***********
二、CyclicBarrier
CyclicBarrier的字面意思是可循环(Cyclic)使用的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活,线程进入屏障通过CyclicBarrier的await()方法,当调用await()方法之后,线程就处于barrier了。
代码测试:收集七颗龙珠,召唤神龙。
public class CyclicBarrierDemo { public static void main(String[] args) { CyclicBarrier barrier = new CyclicBarrier(7, () -> { System.out.println("**********召唤神龙**********"); }); for (int i = 1; i <= 7; i++){ new Thread(()->{ System.out.println("第" + Thread.currentThread().getName() + " 颗龙珠被收集"); try { barrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } }, String.valueOf(i)).start(); } } }
输出结果:
第1 颗龙珠被收集
第7 颗龙珠被收集
第6 颗龙珠被收集
第5 颗龙珠被收集
第4 颗龙珠被收集
第3 颗龙珠被收集
第2 颗龙珠被收集
**********召唤神龙**********
三、Semaphore
Semaphore翻译成字面意思为信号量,Semaphore可以控同时访问的线程个数,通过 acquire() 获取一个许可,如果没有就等待,而 release() 释放一个许可。
信号量主要用于两个目的,一个是用于多个共享资源的互斥使用,另一个是用于并发线程数的控制。
代码实现小案例:6辆汽车抢夺3个停车位。
public class SemaphoreDemo { public static void main(String[] args) { Semaphore semaphore = new Semaphore(3); for (int i = 1; i <= 6; i++){ new Thread(()->{ try { // 获取资源 semaphore.acquire(); System.out.println(Thread.currentThread().getName() + "号车获得停车位"); TimeUnit.SECONDS.sleep(3); System.out.println(Thread.currentThread().getName() + "号车停车3秒离开停车位"); } catch (InterruptedException e) { e.printStackTrace(); }finally { // 释放资源 semaphore.release(); } },String.valueOf(i)).start(); } } }
输出结果:
1号车获得停车位
3号车获得停车位
4号车获得停车位
4号车停车3秒离开停车位
3号车停车3秒离开停车位
5号车获得停车位
1号车停车3秒离开停车位
6号车获得停车位
2号车获得停车位
6号车停车3秒离开停车位
5号车停车3秒离开停车位
2号车停车3秒离开停车位
Process finished with exit code 0