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

CountDownLatch

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

import java.util.concurrent.CountDownLatch;

public class CountDownLatchTest2 {
public static void main(String[] args) {
// 创建计数器,初始化为2
final CountDownLatch latch = new CountDownLatch(2); new Thread(() -> {
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(() -> {
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正在执行
等待2个子线程执行完毕...
子线程Thread-1正在执行
子线程Thread-0执行完毕
子线程Thread-1执行完毕
2个子线程已经执行完毕
继续执行主线程



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

CyclicBarrier 循环栅栏

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

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


import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier; public class CyclicBarrierTest {
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-1正在写入数据...
线程Thread-2正在写入数据...
线程Thread-3正在写入数据...
线程Thread-0写入数据完毕,等待其他线程写入完毕
线程Thread-1写入数据完毕,等待其他线程写入完毕
线程Thread-3写入数据完毕,等待其他线程写入完毕
线程Thread-2写入数据完毕,等待其他线程写入完毕
所有线程写入完毕,继续处理其他任务...
所有线程写入完毕,继续处理其他任务...
所有线程写入完毕,继续处理其他任务...
所有线程写入完毕,继续处理其他任务...

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


import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier; public class CyclicBarrierTest3 {
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();
} try {
Thread.sleep(25000);
} catch (InterruptedException e) {
e.printStackTrace();
} System.out.println("CyclicBarrier重用"); 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.currentThread().getName()+"所有线程写入完毕,继续处理其他任务...");
}
} }

输出:

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

Semaphore信号量

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



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


import java.util.concurrent.Semaphore; public class SemaphoreTest {
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();
}
}
}
}

输出:

工人0占用一个机器在生产...
工人1占用一个机器在生产...
工人2占用一个机器在生产...
工人3占用一个机器在生产...
工人4占用一个机器在生产...
工人1释放出机器
工人0释放出机器
工人4释放出机器
工人5占用一个机器在生产...
工人2释放出机器
工人7占用一个机器在生产...
工人3释放出机器
工人6占用一个机器在生产...
工人5释放出机器
工人6释放出机器
工人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. AJAX-DOM事件

    1.DOM事件 1.select的onchange事件 当选项框中的内容发生改变时需要出发的事件.2.Ajax 1.名词解释 1.同步 在一个任务进行中,不能开启其它的任务. 同步访问:浏览器在向服务 ...

  2. oracle远程连接

    1.1.1    修改文件: 1.1.2    修改net Manager(可省略) 1.1.3    修改任何都需要重启oracle监听和启动服务

  3. vue的子传父

    子组件传值给父组件,需要触发一个事件. 在这个事件里,使用this.$emit("父组件使用的名称","子组件的数据") 在父组件中引用的子组件,在子组件的标签 ...

  4. java常用设计模式四:观察者模式

    1.定义 观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一主题对象.这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己.观察者模式又叫发布-订阅(Publis ...

  5. 学习devexpresschartControl控件

    devexpress官网chart:https://documentation.devexpress.com/WindowsForms/8117/Controls-and-Libraries/Char ...

  6. svn更新的时候出现ERROR:Previous operation has not finished,run "clean up" if it wa interrupted;进行clean up命令也报错

    报错的截图: 然后进行了clean up命令,依旧报错了: 这种情况就有两种方法去解决了,自己可以根据自己的情况选择,哪种方便选择哪种呗! 方法一: 备份自己修改的文件,删除之前download的文件 ...

  7. Mybatis-Plus 实战完整学习笔记(十一)------条件构造器删除,修改,conditon

    1.修改功能--其他过滤方式跟select一样 /** * 修改条件构造器 * @throws SQLException */ @Test public void selectUpdate() thr ...

  8. HDU 1079 Calendar Game (博弈或暴搜)

    题意:给定一个日期,然后 A 和 B 双方进行操作,谁先把日期变成2001年11月04日,将获胜,如果超过该日期,则输了,就两种操作. 第一种:变成下一天,比如现在是2001.11.3 变成 2001 ...

  9. maven使用中遇到的问题

    一>手动将jar包安装到仓库的命令示例: 首先:编写命令:mvn install:install-file -Dfile=D:\lucene-highlighter-4.10.2.jar -Dg ...

  10. Vue上传文件:ElementUI中的upload实现

    一.上传文件实现 两种实现方式: 1.直接action <el-upload  .利用before-upload属性 此种方式有个弊端,就是action是必选的参数,那么action如果和pos ...