本文从实际场景出发,对j.u.c包下的四个并发工具的使用进行演示。相信看完以后会对他们的区别和关联有更多了解。
 CyclicBarrier
j.u.c.CyclicBarrier中文翻译循环栅栏,即可以在多个线程都执行完成后再触发,且支持循环使用。
 场景一
下面场景是5个客人相约到饭店吃饭,只有都到了才能点餐。parties设置为5,会等待5个线程都执行到await()处才会进行下一步。
 代码
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 
 | public class TestCyclicBarrier {
 public static void main(String[] args) {
 
 
 CyclicBarrier cyclicBarrier = new CyclicBarrier(5,
 () -> System.out.println("客人都已到达"));
 
 
 for (int i = 0; i < 5; i++) {
 int finalI = i;
 Runnable runnable = () -> {
 try {
 
 TimeUnit.SECONDS.sleep(finalI + 1);
 System.out.println(Thread.currentThread().getName() + "到达");
 
 cyclicBarrier.await();
 System.out.println(Thread.currentThread().getName() + "点餐");
 
 } catch (Exception e) {
 e.printStackTrace();
 }
 };
 Thread thread = new Thread(runnable);
 thread.setName("客人" + (i + 1));
 thread.start();
 }
 }
 }
 
 | 
 结果
5个人都到了才能点餐
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | 客人1到达客人2到达
 客人3到达
 客人4到达
 客人5到达
 客人都已到达
 客人5点餐
 客人1点餐
 客人2点餐
 客人4点餐
 客人3点餐
 
 | 

 场景二
下面场景是拼单模式,只要有2个客人就能拼单成功,没有拼到就会一直等待。
parties设置为2,每当有2个线程执行到await()处就会进行下一步,第三轮由于只有一个线程,则会一直等待。
 代码
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 
 | public class TestCyclicBarrier {
 public static void main(String[] args) {
 
 
 CyclicBarrier cyclicBarrier = new CyclicBarrier(2,
 () -> System.out.println("客人都已到达"));
 
 for (int i = 0; i < 5; i++) {
 int finalI = i;
 Runnable runnable = () -> {
 try {
 
 TimeUnit.SECONDS.sleep(finalI + 1);
 System.out.println(Thread.currentThread().getName() + "到达");
 
 cyclicBarrier.await();
 System.out.println(Thread.currentThread().getName() + "点餐");
 
 } catch (Exception e) {
 e.printStackTrace();
 }
 };
 Thread thread = new Thread(runnable);
 thread.setName("客人" + (i + 1));
 thread.start();
 }
 }
 }
 
 | 
 结果
客人5只能看着
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | 客人1到达客人2到达
 客人都已到达
 客人2点餐
 客人1点餐
 客人3到达
 客人4到达
 客人都已到达
 客人3点餐
 客人4点餐
 客人5到达
 
 | 

 CountDownLatch
j.u.c.CountDownLatch意为倒计时门闩,一般用作主线程等所有线程都执行完毕后,再执行自己的逻辑。或者等门闩开启,多个线程同时执行。
 场景一
下面场景是等员工都下班了,保安负责给办公室关灯。
设定了count=5,每一个线程调用countDown(),则count–。当count=0时,门闩打开,给主线程放行。
 代码
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 
 | public class TestCountDownLatch {public static void main(String[] args) throws InterruptedException {
 
 CountDownLatch countDownLatch = new CountDownLatch(5);
 
 for (int i = 0; i < 5; i++) {
 int finalI = i;
 Runnable runnable = () -> {
 try {
 
 TimeUnit.SECONDS.sleep(finalI + 1);
 System.out.println(Thread.currentThread().getName() + "下班");
 
 countDownLatch.countDown();
 
 } catch (Exception e) {
 e.printStackTrace();
 }
 };
 Thread thread = new Thread(runnable);
 thread.setName("员工" + (i + 1));
 thread.start();
 }
 
 
 System.out.println("下班时间到,保安在等待关灯。。。");
 countDownLatch.await();
 System.out.println("关灯");
 
 }
 }
 
 | 
 结果一
| 12
 3
 4
 5
 6
 7
 
 | 下班时间到,保安在等待关灯。。。员工1下班
 员工2下班
 员工3下班
 员工4下班
 员工5下班
 关灯
 
 | 

 结果二
如果不设置门闩,运行结果是
| 12
 3
 4
 5
 6
 7
 
 | 下班时间到,保安在等待关灯。。。关灯
 员工1下班
 员工2下班
 员工3下班
 员工4下班
 员工5下班
 
 | 

这样就得摸黑下班了( ´•̥ו̥` )
 场景二
下面场景是员工陆续下班后,等待班车发车,然后一起出发。
设定了count=1,当执行了countDown(),所有阻塞在await()的线程会同时启动
 代码
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 
 | public class TestCountDownLatch2 {public static void main(String[] args) throws InterruptedException {
 
 CountDownLatch countDownLatch = new CountDownLatch(1);
 
 for (int i = 0; i < 5; i++) {
 int finalI = i;
 Runnable runnable = () -> {
 try {
 
 TimeUnit.SECONDS.sleep(finalI + 1);
 System.out.println(Thread.currentThread().getName() + "下班,等车中");
 
 countDownLatch.await();
 System.out.println(Thread.currentThread().getName() + "出发");
 
 } catch (Exception e) {
 e.printStackTrace();
 }
 };
 Thread thread = new Thread(runnable);
 thread.setName("员工" + (i + 1));
 thread.start();
 }
 
 
 TimeUnit.SECONDS.sleep(6);
 System.out.println("到点了");
 countDownLatch.countDown();
 }
 }
 
 | 
 结果
早下班也没用,班车没来
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | 员工1下班,等车中员工2下班,等车中
 员工3下班,等车中
 员工4下班,等车中
 员工5下班,等车中
 到点了
 员工1出发
 员工5出发
 员工4出发
 员工2出发
 员工3出发
 
 | 

 Semaphore
j.u.c.Semaphore意为信号量,可以理解为资源许可证,只有拿到许可证的线程,才能执行对应的工作,在执行完后需要归还。
 场景一
下面场景是公司的餐厅座位有限,员工只能排队用餐。
设置permits=2,表示只有2张许可证,拿不到许可的线程只能等待
 代码
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 
 | public static void main(String[] args) {
 
 Semaphore semaphore = new Semaphore(2);
 
 for (int i = 0; i < 5; i++) {
 Runnable runnable = () -> {
 try {
 
 semaphore.acquire();
 System.out.println(Thread.currentThread().getName() + "到达餐厅开始吃饭");
 
 TimeUnit.SECONDS.sleep(2);
 System.out.println(Thread.currentThread().getName() + "吃完了离开餐厅");
 
 semaphore.release();
 
 } catch (Exception e) {
 e.printStackTrace();
 }
 };
 
 Thread thread = new Thread(runnable);
 thread.setName("员工" + (i + 1));
 thread.start();
 }
 }
 
 | 
 结果
到底什么公司这么坑啊!!
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | 员工1到达餐厅开始吃饭员工2到达餐厅开始吃饭
 员工2吃完了离开餐厅
 员工1吃完了离开餐厅
 员工3到达餐厅开始吃饭
 员工4到达餐厅开始吃饭
 员工4吃完了离开餐厅
 员工3吃完了离开餐厅
 员工5到达餐厅开始吃饭
 员工5吃完了离开餐厅
 
 | 

 Exchanger
j.u.c.Exchanger意为交换机,可以使两个线程在执行exchange()时交换信息。
未完待续。。。
 场景一
 代码
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 
 | public class TestExchanger {
 public static void main(String[] args) {
 
 Exchanger<Object> exchanger = new Exchanger<>();
 
 Runnable runnable = () -> {
 try {
 String field = "咖啡";
 Object o = exchanger.exchange(field);
 System.out.println(Thread.currentThread().getName() + " 用 " + field + " 换了 " + o);
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 };
 Thread thread = new Thread(runnable);
 thread.setName("员工A");
 thread.start();
 
 Runnable runnable2 = () -> {
 try {
 String field = "奶茶";
 Object o = exchanger.exchange(field);
 System.out.println(Thread.currentThread().getName() + " 用 " + field + " 换了 " + o);
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 };
 Thread thread2 = new Thread(runnable2);
 thread2.setName("员工B");
 thread2.start();
 }
 }
 
 | 
 结果
| 12
 
 | 员工B 用 奶茶 换了 咖啡员工A 用 咖啡 换了 奶茶
 
 | 
