在Java里面有几种可以用于控制线程状态的方法,如CountDownLatch计数器、CyclicBarrier循环栅栏、Sempahore信号量。下面就分别演示下他们的使用方法:

CountDownLatch

CountDownLatch可以实现多线程之间的计数器,并实现阻塞功能。比如某个任务依赖于其他的两个任务,只有那两个任务执行结束后,它才能执行。

  1. import java.util.concurrent.CountDownLatch;
  2. public class CountDownLatchTest2 {
  3. public static void main(String[] args) {
  4. // 创建计数器,初始化为2
  5. final CountDownLatch latch = new CountDownLatch(2);
  6. new Thread(() -> {
  7. try {
  8. System.out.println("子线程"+Thread.currentThread().getName()+"正在执行");
  9. Thread.sleep(3000);
  10. System.out.println("子线程"+Thread.currentThread().getName()+"执行完毕");
  11. latch.countDown();// 减一
  12. } catch (InterruptedException e) {
  13. e.printStackTrace();
  14. }
  15. }).start();
  16. new Thread(() -> {
  17. try {
  18. System.out.println("子线程"+Thread.currentThread().getName()+"正在执行");
  19. Thread.sleep(3000);
  20. System.out.println("子线程"+Thread.currentThread().getName()+"执行完毕");
  21. latch.countDown();
  22. } catch (InterruptedException e) {
  23. e.printStackTrace();
  24. }
  25. }).start();
  26. try {
  27. System.out.println("等待2个子线程执行完毕...");
  28. // 阻塞
  29. latch.await();
  30. System.out.println("2个子线程已经执行完毕");
  31. System.out.println("继续执行主线程");
  32. } catch (InterruptedException e) {
  33. e.printStackTrace();
  34. }
  35. }
  36. }

执行的结果:

  1. 子线程Thread-0正在执行
  2. 等待2个子线程执行完毕...
  3. 子线程Thread-1正在执行
  4. 子线程Thread-0执行完毕
  5. 子线程Thread-1执行完毕
  6. 2个子线程已经执行完毕
  7. 继续执行主线程



如上图所示,线程1需要另两个线程结束后,才能继续执行。那么就可以在两个县城里面执行countDown(),然后主线程调用await()进行阻塞。

CyclicBarrier 循环栅栏

它有两层含义,一个是栅栏,一个是循环。先看栅栏,意思就是想一堵墙一样,可以同时对多个线程状态进行管理。

如图所示,几个线程必须同时执行完,才能继续:


  1. import java.util.concurrent.BrokenBarrierException;
  2. import java.util.concurrent.CyclicBarrier;
  3. public class CyclicBarrierTest {
  4. public static void main(String[] args) {
  5. int N = 4;
  6. CyclicBarrier barrier = new CyclicBarrier(N);
  7. for(int i=0;i<N;i++) {
  8. new Writer(barrier).start();
  9. }
  10. }
  11. static class Writer extends Thread{
  12. private CyclicBarrier cyclicBarrier;
  13. public Writer(CyclicBarrier cyclicBarrier) {
  14. this.cyclicBarrier = cyclicBarrier;
  15. }
  16. @Override
  17. public void run() {
  18. System.out.println("线程"+Thread.currentThread().getName()+"正在写入数据...");
  19. try {
  20. Thread.sleep(5000); //以睡眠来模拟写入数据操作
  21. System.out.println("线程"+Thread.currentThread().getName()+"写入数据完毕,等待其他线程写入完毕");
  22. cyclicBarrier.await();
  23. } catch (InterruptedException e) {
  24. e.printStackTrace();
  25. }catch(BrokenBarrierException e){
  26. e.printStackTrace();
  27. }
  28. System.out.println("所有线程写入完毕,继续处理其他任务...");
  29. }
  30. }
  31. }

输出:

  1. 线程Thread-0正在写入数据...
  2. 线程Thread-1正在写入数据...
  3. 线程Thread-2正在写入数据...
  4. 线程Thread-3正在写入数据...
  5. 线程Thread-0写入数据完毕,等待其他线程写入完毕
  6. 线程Thread-1写入数据完毕,等待其他线程写入完毕
  7. 线程Thread-3写入数据完毕,等待其他线程写入完毕
  8. 线程Thread-2写入数据完毕,等待其他线程写入完毕
  9. 所有线程写入完毕,继续处理其他任务...
  10. 所有线程写入完毕,继续处理其他任务...
  11. 所有线程写入完毕,继续处理其他任务...
  12. 所有线程写入完毕,继续处理其他任务...

循环的意思就是当计数减到0时,还可以继续使用,如:


  1. import java.util.concurrent.BrokenBarrierException;
  2. import java.util.concurrent.CyclicBarrier;
  3. public class CyclicBarrierTest3 {
  4. public static void main(String[] args) {
  5. int N = 4;
  6. CyclicBarrier barrier = new CyclicBarrier(N);
  7. for(int i=0;i<N;i++) {
  8. new Writer(barrier).start();
  9. }
  10. try {
  11. Thread.sleep(25000);
  12. } catch (InterruptedException e) {
  13. e.printStackTrace();
  14. }
  15. System.out.println("CyclicBarrier重用");
  16. for(int i=0;i<N;i++) {
  17. new Writer(barrier).start();
  18. }
  19. }
  20. static class Writer extends Thread{
  21. private CyclicBarrier cyclicBarrier;
  22. public Writer(CyclicBarrier cyclicBarrier) {
  23. this.cyclicBarrier = cyclicBarrier;
  24. }
  25. @Override
  26. public void run() {
  27. System.out.println("线程"+Thread.currentThread().getName()+"正在写入数据...");
  28. try {
  29. Thread.sleep(5000); //以睡眠来模拟写入数据操作
  30. System.out.println("线程"+Thread.currentThread().getName()+"写入数据完毕,等待其他线程写入完毕");
  31. cyclicBarrier.await();
  32. } catch (InterruptedException e) {
  33. e.printStackTrace();
  34. }catch(BrokenBarrierException e){
  35. e.printStackTrace();
  36. }
  37. System.out.println(Thread.currentThread().getName()+"所有线程写入完毕,继续处理其他任务...");
  38. }
  39. }
  40. }

输出:

  1. 线程Thread-0正在写入数据...
  2. 线程Thread-2正在写入数据...
  3. 线程Thread-3正在写入数据...
  4. 线程Thread-1正在写入数据...
  5. 线程Thread-2写入数据完毕,等待其他线程写入完毕
  6. 线程Thread-0写入数据完毕,等待其他线程写入完毕
  7. 线程Thread-1写入数据完毕,等待其他线程写入完毕
  8. 线程Thread-3写入数据完毕,等待其他线程写入完毕
  9. Thread-3所有线程写入完毕,继续处理其他任务...
  10. Thread-1所有线程写入完毕,继续处理其他任务...
  11. Thread-0所有线程写入完毕,继续处理其他任务...
  12. Thread-2所有线程写入完毕,继续处理其他任务...
  13. CyclicBarrier重用
  14. 线程Thread-4正在写入数据...
  15. 线程Thread-5正在写入数据...
  16. 线程Thread-6正在写入数据...
  17. 线程Thread-7正在写入数据...
  18. 线程Thread-4写入数据完毕,等待其他线程写入完毕
  19. 线程Thread-7写入数据完毕,等待其他线程写入完毕
  20. 线程Thread-5写入数据完毕,等待其他线程写入完毕
  21. 线程Thread-6写入数据完毕,等待其他线程写入完毕
  22. Thread-6所有线程写入完毕,继续处理其他任务...
  23. Thread-7所有线程写入完毕,继续处理其他任务...
  24. Thread-4所有线程写入完毕,继续处理其他任务...
  25. Thread-5所有线程写入完毕,继续处理其他任务...

Semaphore信号量

这个东西有点像连接池的感觉,某一时间只有几个线程能拿到资源,执行操作。



比如下面车间工人在排队使用机器的例子:


  1. import java.util.concurrent.Semaphore;
  2. public class SemaphoreTest {
  3. public static void main(String[] args) {
  4. int N = 8; //工人数
  5. Semaphore semaphore = new Semaphore(5); //机器数目
  6. for(int i=0;i<N;i++) {
  7. new Worker(i, semaphore).start();
  8. }
  9. }
  10. static class Worker extends Thread{
  11. private int num;
  12. private Semaphore semaphore;
  13. public Worker(int num,Semaphore semaphore){
  14. this.num = num;
  15. this.semaphore = semaphore;
  16. }
  17. @Override
  18. public void run() {
  19. try {
  20. semaphore.acquire();
  21. System.out.println("工人"+this.num+"占用一个机器在生产...");
  22. Thread.sleep(2000);
  23. System.out.println("工人"+this.num+"释放出机器");
  24. semaphore.release();
  25. } catch (InterruptedException e) {
  26. e.printStackTrace();
  27. }
  28. }
  29. }
  30. }

输出:

  1. 工人0占用一个机器在生产...
  2. 工人1占用一个机器在生产...
  3. 工人2占用一个机器在生产...
  4. 工人3占用一个机器在生产...
  5. 工人4占用一个机器在生产...
  6. 工人1释放出机器
  7. 工人0释放出机器
  8. 工人4释放出机器
  9. 工人5占用一个机器在生产...
  10. 工人2释放出机器
  11. 工人7占用一个机器在生产...
  12. 工人3释放出机器
  13. 工人6占用一个机器在生产...
  14. 工人5释放出机器
  15. 工人6释放出机器
  16. 工人7释放出机器

总结

  1. CountDownLatch 可以实现计数等待,主要用于某个线程等待其他几个线程
  2. CyclicBarrier 实现循环栅栏,主要用于多个线程同时等待其他线程
  3. Semaphore 信号量,主要强调只有某些个数量的线程能拿到资源执行

参考

Java计数器之CountDownLatch、CyclicBarrier、Semaphore的更多相关文章

  1. Java并发编程工具类 CountDownLatch CyclicBarrier Semaphore使用Demo

    Java并发编程工具类 CountDownLatch CyclicBarrier Semaphore使用Demo CountDownLatch countDownLatch这个类使一个线程等待其他线程 ...

  2. CountDownLatch/CyclicBarrier/Semaphore 使用过吗?

    CountDownLatch/CyclicBarrier/Semaphore 使用过吗?下面详细介绍用法: 一,(等待多线程完成的)CountDownLatch  背景; countDownLatch ...

  3. 并发包下常见的同步工具类详解(CountDownLatch,CyclicBarrier,Semaphore)

    目录 1. 前言 2. 闭锁CountDownLatch 2.1 CountDownLatch功能简介 2.2 使用CountDownLatch 2.3 CountDownLatch原理浅析 3.循环 ...

  4. 并发包下常见的同步工具类(CountDownLatch,CyclicBarrier,Semaphore)

    在实际开发中,碰上CPU密集且执行时间非常耗时的任务,通常我们会选择将该任务进行分割,以多线程方式同时执行若干个子任务,等这些子任务都执行完后再将所得的结果进行合并.这正是著名的map-reduce思 ...

  5. 转发---[沧海拾遗]java并发之CountDownLatch、Semaphore和CyclicBarrier

    JAVA并发包中有三个类用于同步一批线程的行为,分别是CountDownLatch.Semaphore和CyclicBarrier. CountDownLatch CountDownLatch是一个计 ...

  6. java并发之CountDownLatch、Semaphore和CyclicBarrier

    JAVA并发包中有三个类用于同步一批线程的行为,分别是CountDownLatch.Semaphore和CyclicBarrier. CountDownLatch Java之CountDownLatc ...

  7. Java中的4个并发工具类 CountDownLatch CyclicBarrier Semaphore Exchanger

    在 java.util.concurrent 包中提供了 4 个有用的并发工具类 CountDownLatch 允许一个或多个线程等待其他线程完成操作,课题点 Thread 类的 join() 方法 ...

  8. 高并发第十单:J.U.C AQS(AbstractQueuedSynchronizer) 组件:CountDownLatch. CyclicBarrier .Semaphore

    这里有一篇介绍AQS的文章 非常好: Java并发之AQS详解 AQS全名:AbstractQueuedSynchronizer,是并发容器J.U.C(java.lang.concurrent)下lo ...

  9. 多线程中 CountDownLatch CyclicBarrier Semaphore的使用

    CountDownLatch 调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行.也可以传入时间,表示时间到之后,count还没有为0的时候,就会继续执行. package ...

随机推荐

  1. input.text文件提示效果

    <div class="search"><input type="text" value="Seach Products" ...

  2. springboot深入学习(四)-----tomcat配置、websocket

    一.更改servlet服务器 springboot中默认可以集成多种servlet容器,当引入如下依赖时: springboot默认以tomcat作为项目的servlet容器,如果用户想要替换tomc ...

  3. MariaDBConn用于链接MariaDB的管理类

    https://downloads.mariadb.com/Connectors/java/connector-java-2.2.3/ public class MariaDBConn { final ...

  4. maven打包某个分支的包

    maven打某个分支的包命令: mvn clean install -Dmaven.test.skip=true -Pdevelop

  5. eclipse 创建servlet 出现继承 HttpServlet 报红线

    eclipse创建servlet出现红线: 解决方案1,鼠标右键项目 -> 鼠标右击项目——>Build Path——> 点击comfigure Build Path进入-----& ...

  6. 手机布局rem的使用(rem)

    最后一堆代码是举例的全码. 一 直接<head>标签里套用以下,其他都不用 <script> document.documentElement.style.fontSize = ...

  7. flex 布局 计算器

    flex布局计算器 <!doctype html> <html> <head> <style> .box{ display: flex; flex-di ...

  8. .NET 开源GIS项目

    SharpMapSharpMap是一个基于.NET 2.0使用C#开发的Map渲染类库,可以渲染ESRI Shape.PostGIS.MS SQL等格式的GIS数据,通过扩展地图数据Provider, ...

  9. jq+download+文件夹下载

    最近公司在做工程项目,实现文件夹下载. 网上找了很久,发现网上的代码都有相似的问题,不过最终还是让我找到了一个符合的项目. 工程: 进行项目文件夹下载功能分析,弄清楚文件夹下载的原理,提供的数据支持. ...

  10. 微信官方api & 非官方api

    1.微信公众平台开发者文档 http://mp.weixin.qq.com/wiki/home/index.html 2.微信公众平台 https://mp.weixin.qq.com/ 3.第三方a ...