上次简单了解了多线程中锁的类型,今天要简单了解下多线程并发控制的一些工具类了。

1. 概念说明:

CountDownLatch:相当于一个待执行线程计数器,当计数减为零时表示所有待执行线程都已执行完毕,等待被计数线程结果的(即使用await()的)线程可以继续执行(await()后面的代码)了。

CyclicBarrier:可循环屏障,相当于一个准备执行线程计数器,当计数减为零时表示所有待执行线程(这些线程需要同时开始工作)都已做好准备工作,可以开始工作了。

Semaphore:允许并发线程数,semaphore.acquire()和semaphore.release()方法总是成对出现,而这对方法之间的代码最多允许多少个线程访问是由Semaphore semaphore=new Semaphore(n)的n决定的。

2. 构造实际场景,使用示例

设想一个赛跑场景,一共有10个运动员参赛,所有运动员必须同时起跑(CyclicBarrier控制),而计分结束必须在所有运动员都跑完全程之后(CountDownLatch控制),但是学校操场只有4条跑道(Semaphore),那么就要让运动员分三批进行比赛,每次最多4人入场:

1 importcom.alibaba.fastjson.JSONObject;2 importorg.apache.commons.lang3.concurrent.BasicThreadFactory;3 importorg.junit.Test;4

5 import java.util.concurrent.*;6

7 public classMultiThreadsTest {8 private volatile ConcurrentHashMap map = new ConcurrentHashMap<>();9 //声明一个线程池,用于线程管理

10 ThreadPoolExecutor executor = new ThreadPoolExecutor(4, 4,11 20, TimeUnit.MICROSECONDS, new LinkedBlockingQueue<>(),12 new BasicThreadFactory.Builder().namingPattern("Runner-%d").build(),13 newThreadPoolExecutor.CallerRunsPolicy());14

15 @Test16 public voidtestMultiControl() {17 //跑道数

18 int runways = 4;19 //参赛总人数

20 int runners = 10;21 //参赛人数多于跑道数,需分批比赛

22 int batch = 1;23 //当运动员总数多于跑道数,最多runways人入场

24 while (runners >=runways) {25 runningGame(batch++, runways);26 runners = runners -runways;27 }28 //最后一批,还剩几个人,就几个人入场

29 runningGame(batch, runners);30 System.out.println("\n所有选手都已跑完,现在宣布比赛结果:\n" +JSONObject.toJSONString(map));31 }32

33 private void runningGame(int batch, intrunners) {34 System.out.println("第" + batch + "批,共" + runners + "人,运动员正在进场...");35 //每批允许runways个运动员入场

36 Semaphore semaphore = newSemaphore(runners);37 //每批runways个运动员必须都准备好,同时起跑

38 CyclicBarrier barrier = newCyclicBarrier(runners);39 //每批runways个运动员都跑完全程,裁判这一批计分结束

40 CountDownLatch latch = newCountDownLatch(runners);41 for (int i = runners; i > 0; i--) {42 //每个运动员都是一个独立奔跑的线程

43 executor.execute(() ->{44 try{45 //每个运动员进场都会占用一个跑道

46 semaphore.acquire();47 //每个运动员就位都会通知barrier,等所有跑道上的运动员都就位,大家就一起跑!

48 barrier.await();49 running(Thread.currentThread().getName());50 //每个运动员跑完都要让出自己的跑道(为下一批运动员让路)

51 semaphore.release();52 } catch(InterruptedException e) {53 e.printStackTrace();54 } catch(BrokenBarrierException e) {55 e.printStackTrace();56 } finally{57 //每个运动员跑完都要通知裁判为自己计分

58 latch.countDown();59 }60 });61 }62 try{63 //跑道上所有运动员都跑完,则裁判计分结束

64 latch.await();65 System.out.println("第" + batch + "批,共" + runners + "人,计分结束");66 } catch(InterruptedException e) {67 System.out.println(e.getStackTrace());68 }69 }70

71 private voidrunning(String name) {72 long start =System.currentTimeMillis();73 System.out.println(name + " running started ...");74 System.out.println(name + ": I'm running.\taudience: Yes, I see.\t" + name + ":I'm done running.\taudience: Well done!");75 try{76 //跑太快,歇会儿

77 TimeUnit.MILLISECONDS.sleep(2);78 } catch(InterruptedException e) {79 e.printStackTrace();80 }81 System.out.println(name + " running completed");82 //裁判将所有运动员的分数都记录在map中

83 map.put(name, (System.currentTimeMillis() - start) + "ms");84 }85 }

运行结果

3. 代码运行结果分析:

乍看上面代码和运行结果好像都没什么问题,每批允许4人进场,总是同时开始跑,也都等到每批选手都跑完后该批计分结束,countDownLatch和CyclicBarrier确实都起到了各自的作用,但是Semaphore呢?好像也确实是限制了只允许4个线程同时访问这段代码,然而在你一次只有4个选手的情况下,它当然是最多4个线程访问了,其实Semaphore的工作已经由方法入参给限定了啊,Semaphore的作用何在呢?那么假如学校原本有4个跑道,但是比赛开始之后却发现有一个入场通道坏了,变成了每次只能有3个人入场,但是场内的裁判并不知道,还在等待着按每4人一批进行比赛,那将会是什么结果呢?

我们修改代码看下:其他部分不变,只把允许入场的运动员数减1,然后再运行Test发现程序一直处于“第一批运动员进场”过程中,说明Semaphore这个变量已经起到了它的作用,就是每次只允许3个运动员进场,而且放入3个运动员后就会进行等待,等待这3个运动员比赛结束再放下一批进场,而场内的裁判并不知道可入场人数已经变化,还在等待着第4名选手入场才吹响开跑号声,因此入场管理员Semaphore和起跑裁判官CyclicBarrier就会陷入无法终止的相互等待,程序一直无法打破这种等待循环,因而进入停滞状态,这就是一种简单的死锁场景了。

4. 总结

这里只是简单说明这三个工具有用法,场景并不十分合理,其实这三者通常独立使用,一般不会碰到三者同时上场的机会。

JAVA所有选手就位后比赛开始_Java多线程-CountDownLatch、CyclicBarrier、Semaphore相关推荐

  1. (面经总结)一篇文章带你完整复习 Java 中并发关键字(CountDownLatch/CyclicBarrier/Semaphore/Volatile)

    文章目录 一.倒计数器:CountDownLatch 二.循环栅栏:CyclicBarrier 三.信号量:Semaphore 四.volatile 关键字的作用 一.倒计数器:CountDownLa ...

  2. Java中Thread中的实例方法_Java多线程2:Thread中的实例方法

    Thread类中的方法调用方式: 学习Thread类中的方法是学习多线程的第一步.在学习多线程之前特别提出一点,调用Thread中的方法的时候,在线程类中,有两种方式,一定要理解这两种方式的区别: 1 ...

  3. java线程栅栏_Java 多线程基础 - CyclicBarrier

    我的博客 转载请注明原创出处. 序 java.util.concurrent包里有几个能帮助人们管理相互合作的线程集的类,为多线程常见的应用场景预置了抽象好的类库.在遇到这些应用场景时应该直接重用合适 ...

  4. java线程初始方法三种_Java 多线程 三种实现方式

    Java多线程实现方式主要有三种:继承Thread类.实现Runnable接 口.使用ExecutorService.Callable 实现有返回结果的多线程.其中前两种方式线程执行完后都没有返回值, ...

  5. java请模拟出双重定时器_Java多线程基础 - osc_czmaebyq的个人空间 - OSCHINA - 中文开源技术交流社区...

    ( 1 ) 传统使用类Thread和接口Runnable实现 1. 在Thread子类覆盖的run方法中编写运行代码 方式一 newThread(){ @Overridepublic voidrun( ...

  6. java线程的创建与执行_Java多线程的创建和运行

    1.多线程的好处 多线程是一个很有用的东西,它使的系统可以同时运行多个任务,提高程序的执行效率.大家平时可能没有注意到,其实我们电脑能同时执行多个程序的基本原理就是多线程. 每一个程序都是一个进程,而 ...

  7. java不同进程的相互唤醒_Java多线程(二)同步与等待唤醒

    1:数据安全问题 1.1:什么情况下会出现数据安全问题? 多个线程对同一个资源进行操作,并且操作资源的语句有多条.那么这个时候这些语句因为cpu的随机性,有可能被多个线程分开执行.导致数据安全问题. ...

  8. java不同进程的相互唤醒_JAVA多线程之线程间的通信方式

    一,介绍 本总结我对于JAVA多线程中线程之间的通信方式的理解,主要以代码结合文字的方式来讨论线程间的通信,故摘抄了书中的一些示例代码. 二,线程间的通信方式 ①同步 这里讲的同步是指多个线程通过sy ...

  9. java中线程调度遵循的原则_Java 多线程(三) 线程的生命周期及优先级

    线程的生命周期 线程的生命周期:一个线程从创建到消亡的过程. 如下图,表示线程生命周期中的各个状态: 线程的生命周期可以分为四个状态: 1.创建状态: 当用new操作符创建一个新的线程对象时,该线程处 ...

最新文章

  1. anaconda怎么使用编写python_怎样使用anaconda编辑python
  2. 卷积神经网络四种卷积类型
  3. android ImageButton的图片怎么定义?
  4. 下载文件旁边附的MD5/SHA256等有什么用途?
  5. 测试工具:Windows下超强日志工具BareTail
  6. GFS分布式文件系统简介及部署——让存储变得更高级
  7. Kubernetes Nginx Ingress教程
  8. sql datetime 排序_超全的数据库建表/SQL/索引规范,建议贴在工位上!
  9. 因特尔显卡自定义分辨率_电脑显示器分辨率超频教程:1080P超2K分辨率的方法...
  10. JavaScript HTML DOM
  11. c++父类和子类转化致命的代码错误
  12. Android的简介
  13. 剑指Offer(Java版):把字符串转换成整数
  14. Ubuntu20.04如何卸载软件
  15. cassandra可视化工具_精华 | 140种Python标准库、第三方库和外部工具都有了
  16. iOS视频播放器开发
  17. 盛帮股份深交所上市:市值24亿 赖喜隆父子为实控人
  18. Python可视化配色方案,分分钟实现配色自由啦~
  19. [golang]简单文件上传服务
  20. rank over pation

热门文章

  1. [图示]做人36字诀:二)形象塑造 ——教你品格高雅
  2. 多态的实现(重载,虚方法,抽象类,接口)
  3. Pycharm使用详解
  4. 利用Bootstrap+Avalonjs+EntityFramework 开发ASP.NET WebForm应用程序(上)
  5. firefox英文网页乱码解决方法
  6. .NET疯狂架构经验分享系列之(七)WCF支持(转)
  7. 思科虚拟化与视频技术打造协作新体验
  8. Cisco热备份路由协议(HSRP) 2
  9. python爬取音乐神器_Python爬虫提取神器,正则表达式(re模块),全程干货!
  10. 【FI模块学习笔记】 固定资产概述(上)