首页 > 其他分享 >JUC 常用 4 大并发工具类 CountDownLatch、CyclicBarrier、Semaphore、ExChanger

JUC 常用 4 大并发工具类 CountDownLatch、CyclicBarrier、Semaphore、ExChanger

时间:2023-03-20 13:05:03浏览次数:38  
标签:JUC permits Semaphore parties 线程 ExChanger CountDownLatch new CyclicBarrier


文章目录

  • ​​什么是JUC?​​
  • ​​4大常用并发工具类​​
  • ​​CountDownLatch​​
  • ​​CyclicBarrier​​
  • ​​Semaphore​​
  • ​​Exchanger​​

JUC 常用 4 大并发工具类 CountDownLatch、CyclicBarrier、Semaphore、ExChanger_java

什么是JUC?

JUC就是java.util.concurrent包,这个包俗称JUC,里面都是解决并发问题的一些定义类,该包的位置位于java下面的rt.jar包下面。

4大常用并发工具类

  • CountDownLatch
  • CyclicBarrier
  • Semaphore
  • ExChanger

CountDownLatch

​​CountDownLatch使用详解​​

CountDownLatch,俗称 闭锁

就比如在启动框架服务的时候,我们主线程需要在环境线程初始化完成之后才能启动,这时候我们就可以实现使用CountDownLatch来完成。

构造方法:

/**
* Constructs a {@code CountDownLatch} initialized with the given count.
*
* @param count the number of times {@link #countDown} must be invoked
* before threads can pass through {@link #await}
* @throws IllegalArgumentException if {@code count} is negative
*/
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}

在源码中可以看到,创建​​CountDownLatch​​时,需要传入一个int类型的参数,将决定在执行次扣减之后,等待的线程被唤醒

JUC 常用 4 大并发工具类 CountDownLatch、CyclicBarrier、Semaphore、ExChanger_jvm_02

方法介绍:

​CountDownLatch​​:初始化方法

​await​​:等待方法,同时带参数的是超时重载方法

​countDown​​:每执行一次,计数器减一,就是初始化传入的数字,也代表着一个线程完成了任务

​getCount​​:获取当前值

​toString​​:这个就不用说了

里面的Sync是一个内部类,外面的方法其实都是操作这个内部类的,这个内部类继承了AQS,实现的标准方法。

JUC 常用 4 大并发工具类 CountDownLatch、CyclicBarrier、Semaphore、ExChanger_java_03

主线程中创建​​CountDownLatch(3)​​,然后主线程await阻塞,然后线程A,B,C各自完成了任务,调用了countDown,之后,每个线程调用一次计数器就会减一,初始是3,然后A线程调用后变成2,B线程调用后变成1,C线程调用后,变成0,这时就会唤醒正在await的主线程,然后主线程继续执行。

CyclicBarrier

​​CyclicBarrier使用​​

CyclicBarrier,俗称 栅栏锁

这个感觉和CountDownLatch有点相似,但是其实是不一样的,所谓的差别,在下面说。

构造参数:

/**
* Creates a new {@code CyclicBarrier} that will trip when the
* given number of parties (threads) are waiting upon it, and which
* will execute the given barrier action when the barrier is tripped,
* performed by the last thread entering the barrier.
*
* @param parties the number of threads that must invoke {@link #await}
* before the barrier is tripped
* @param barrierAction the command to execute when the barrier is
* tripped, or {@code null} if there is no action
* @throws IllegalArgumentException if {@code parties} is less than 1
*/
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
this.barrierCommand = barrierAction;
}

/**
* Creates a new {@code CyclicBarrier} that will trip when the
* given number of parties (threads) are waiting upon it, and
* does not perform a predefined action when the barrier is tripped.
*
* @param parties the number of threads that must invoke {@link #await}
* before the barrier is tripped
* @throws IllegalArgumentException if {@code parties} is less than 1
*/
public CyclicBarrier(int parties) {
this(parties, null);
}

很明显能感觉出来,下面的构造参数调用了下面的构造参数,是一个构造方法重载。

首先这个第一个参数也树Int类型的,传入的是执行线程的个数,这个数量和CountDownLatch不一样,这个数量是需要和线程数量吻合的,CountDownLatch则不一样,CountDownLatch可以大于等于(一个线程内可以countDown不止一次),而CyclicBarrier只能等于,然后是第二个参数,第二个参数是barrierAction,这个参数是当屏障开放后,执行的任务线程,如果当屏障开放后需要执行什么任务,可以写在这个线程中。

JUC 常用 4 大并发工具类 CountDownLatch、CyclicBarrier、Semaphore、ExChanger_java_04

主线程创建​​CyclicBarrier(3,barrierAction)​​,然后由线程开始执行,线程A,B执行完成后都调用了await,然后他们都在一个屏障前阻塞者,需要等待线程C也,执行完成,调用await之后,然后三个线程都达到屏障后,屏障开放,然后线程继续执行,并且barrierAction在屏障开放的一瞬间也开始执行。

CountDownLatch和CyclicBarrier的区别

CountDownLatch的构造参数传入的数量一般都是大于等于线程数量的,因为他是由第三方控制的,可以扣减多次,CyclicBarrier的构造参数第一个参数传入的数量一定是等于线程的个数的,因为他是由一组线程自身控制。

CountDownLatch

CyclicBarrier

控制

第三方控制

自身控制

传入数量

大于等于线程数量

等于线程数量

是否可复用

不可复用

可复用

Semaphore

​​Semaphore使用详解​​

Semaphore,俗称 信号量

构造方法:

/**
* Creates a {@code Semaphore} with the given number of
* permits and nonfair fairness setting.
*
* @param permits the initial number of permits available.
* This value may be negative, in which case releases
* must occur before any acquires will be granted.
*/
public Semaphore(int permits) {
sync = new NonfairSync(permits);
}

/**
* Creates a {@code Semaphore} with the given number of
* permits and the given fairness setting.
*
* @param permits the initial number of permits available.
* This value may be negative, in which case releases
* must occur before any acquires will be granted.
* @param fair {@code true} if this semaphore will guarantee
* first-in first-out granting of permits under contention,
* else {@code false}
参数fair表示是否是公平的,即等待时间越久的越先获取许可
*/
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}

在源码中可以看到在构建Semaphore信号量的时候,需要传入许可证的数量,这个数量就是资源的最大允许的访问的线程数。

Exchanger

Exchanger,俗称交换器,用于在线程之间交换数据,但是比较受限,因为只能两个线程之间交换数据。

构造方法:

/**
* Creates a new Exchanger.
*/
public Exchanger() {
participant = new Participant();
}

构造函数没有入参,只有在创建的时候指定一下需要交换的数据的泛型即可,下面看代码

代码示例:

/**
* @description: 线程之间交换数据
* @author: yh
* @date: 2023/2/5
*/
public class UseExchange {
private static final Exchanger<Set<String>> exchanger = new Exchanger<>();

public static void main(String[] args) {

new Thread(){
@Override
public void run() {
Set<String> aSet = new HashSet<>();
aSet.add("A");
aSet.add("B");
aSet.add("C");
try {
Set<String> exchange = exchanger.exchange(aSet);
for (String s : exchange) {
System.out.println("aSet:"+s);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();

new Thread(){
@Override
public void run() {
Set<String> bSet = new HashSet<>();
bSet.add("1");
bSet.add("2");
bSet.add("3");
try {
Set<String> exchange = exchanger.exchange(bSet);
for (String s : exchange) {
System.out.println("bSet:"+s);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();

}
}

执行结果:

bSet:A
aSet:1
bSet:B
aSet:2
bSet:C
aSet:3

通过执行结果可以清晰的看到,两个线程中的数据发生了交换,这就是Exchanger的线程数据交换了。

以上就是JUC的4大常用并发工具类。


标签:JUC,permits,Semaphore,parties,线程,ExChanger,CountDownLatch,new,CyclicBarrier
From: https://blog.51cto.com/u_14452299/6132588

相关文章

  • JUC源码学习笔记8——ConcurrentHashMap源码分析1 如何实现低粒度锁的插入,如何实现统
    源码基于jdk1.8这一片主要讲述ConcurrentHashMap如何实现低粒度锁的插入,如何实现统计元素个数,如何实现并发扩容迁移系列文章目录和关于我一丶ConcurrentHashMap概述......
  • JUC提供了哪些阻塞队列
    阻塞队列的处理方法阻塞队列实现了BlockingQueue接口,并且有多组处理方法。抛出异常add方式是往队列里面添加元素,如果队里队列满了,会抛出异常remove方法是删除元素,如......
  • 测试JUC安全类型的集合
    packageedu.wtbu;importjava.util.concurrent.CopyOnWriteArrayList;//测试JUC安全类型的集合publicclassDemo09{publicstaticvoidmain(String[]args){......
  • 【并发编程六】c++进程通信——信号量(semaphore)
     【并发编程六】c++进程通信——信号量(semaphore)一、概述二、信号量三、原理四、过程1、进程A过程2、进程B过程五、demo1、进程A2、进程B六、输出......
  • JUC-CopyOnWriteArrayList
    packagesyn;importjava.util.concurrent.CopyOnWriteArrayList;publicclassTestJUC{publicstaticvoidmain(String[]args){CopyOnWriteArrayListlist=new......
  • windows 使用 Semaphore 进行同步
    使用Semaphore进行线程同步#include<windows.h>#include<stdio.h>#defineMAX_SEM_COUNT2#defineTHREADCOUNT3HANDLEghSemaphore;DWORDWINAPIThreadProc(......
  • JUC(四)多线程锁
    目录多线程锁Synchronized锁的八种情况公平锁和非公平锁可重入锁synchronizedLock死锁检查死锁多线程锁Synchronized锁的八种情况以一个手机类为例,包含两个synchronized......
  • JUC(七)分支合并框架
    JUC分支合并框架简介Fork/Join可以将一个大的任务拆分成多个子任务进行并行处理,最后将子任务的结果合并称为最终的计算结果。Fork:负责将任务拆分Join:合并拆分任务For......
  • JUC(五)Callable
    Callable接口创建线程的几种方式继承Thread类实现Runnable接口通过Callable接口线程池使用Runnable接口无法获取到线程返回的结果,因此在jdk1.5后java提供了Callabl......
  • JUC(八)ThreadLocal
    ThreadLocal简介ThreadLocal提供局部线程变量,这个变量与普通的变量不同,每个线程在访问ThreadLocal实例的时候,(通过get或者set方法)都有自己的、独立初始化变量副本。Threa......