首页 > 其他分享 >JUC 常用 4 大并发工具类

JUC 常用 4 大并发工具类

时间:2023-02-05 16:01:17浏览次数:70  
标签:JUC 常用 code permits 并发 线程 CountDownLatch new CyclicBarrier

2023-02-05-15-19-52.png

什么是JUC?

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

4大常用并发工具类

  • CountDownLatch
  • CyclicBarrier
  • Semaphore
  • ExChanger

CountDownLatch

CountDownLatch使用详解

CountDownLatch,俗称 <font color="red">闭锁</font> ,作用是类似加强版的Join,是让一组线程等待其他的线程完成工作以后才执行。

就比如在启动框架服务的时候,我们主线程需要在环境线程初始化完成之后才能启动,这时候我们就可以实现使用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类型的参数,将决定在执行次扣减之后,等待的线程被唤醒

2023-02-05-14-17-14.png

方法介绍:

CountDownLatch:初始化方法

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

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

getCount:获取当前值

toString:这个就不用说了

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

2023-02-05-14-20-25.png

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

CyclicBarrier

CyclicBarrier使用

CyclicBarrier,俗称 <font color=red>栅栏锁</font> ,作用是让一组线程到达某个屏障,被阻塞,一直到组内的最后一个线程到达,然后屏障开放,接着所有的线程继续运行。

这个感觉和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,这个参数是当屏障开放后,执行的任务线程,如果当屏障开放后需要执行什么任务,可以写在这个线程中。

2023-02-05-14-26-47.png

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

CountDownLatch和CyclicBarrier的区别

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

CountDownLatch CyclicBarrier
控制   第三方控制      自身控制
传入数量   大于等于线程数量 等于线程数量
是否可复用 不可复用 可复用

Semaphore

Semaphore使用详解

Semaphore,俗称 <font color=red>信号量</font> ,作用于控制同时访问某个特定资源的线程数量,用在流量控制。

构造方法:

/**
* 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,常用,code,permits,并发,线程,CountDownLatch,new,CyclicBarrier
From: https://blog.51cto.com/u_14452299/6038300

相关文章

  • 常用类
    常用类内部类概念:在一个类的内部再定义一个完整的类特点:编译之后可生成独立的字节码文件内部类可直接访问外部类的私有成员,而不破坏封装可为外部类提供必要的......
  • vscode常用快捷键
    1.介绍本文主要介绍vscode的一些常用快捷键的使用.2.打开命令面板按下F1或Ctrl+Shift+P可以打开命令面板在打开的输入框内,可以输入任何命令按一下Backspace会......
  • 八种常用的排序算法
    八种常用的排序算法对各种常用的排序算法的代码实现、时间复杂度、空间复杂度、稳定性做简要分析。Author:MsuenbDate:2023-01-31概述排序也称排序算法(SortAlgo......
  • Go sync并发工具包
    简介在Java中提供Sychronized关键字提供独占锁,Lock类提供读写锁。在sync包中实现的功能也是与锁相关,包中主要包含的有:sync.Map:并发安全mapsync.Mutex:锁sync.RWMutex:......
  • Java多线程并发04—线程池的合理使用
    为什么使用线程池?线程池做的工作主要是控制运行的线程的数量。线程池的种类Java中常用的线程池主要有四种:newCachedThreadPool、newFixedThreadPool、newScheduledThreadPo......
  • Java多线程并发05-锁说明
    根据锁的各种特性,可将锁分为以下几类:乐观锁/悲观锁独享锁(互斥锁)/共享锁(读写锁)可重入锁公平锁/非公平锁分段锁偏向锁/轻量级锁/重量级锁自旋锁乐观锁/悲观锁乐观锁与悲观锁并......
  • Mac上Homebrew常用命令
    Mac上Homebrew常用命令官方网址https://brew.sh/常用命令安装(官方方法)/bin/bash-c"$(curl-fsSLhttps://raw.githubusercontent.com/Homebrew/install/HEAD/inst......
  • GO 并发
    简介Go语言支持并发,我们只需要通过go关键字来开启goroutine即可。goroutine是轻量级线程也有叫用户级线程,协程的,goroutine的调度是由Golang运行时进行......
  • Docker常用指令
    run  创建一个新的容器。  #使用docker镜像nginx:latest以后台模式启动一个容器#并将容器命名为mynginxdockerrun--namemynginx-dnginx:latest#使......
  • python基础:数据类型、与用户交互、格式化输出、基本运算符号、常用赋值符号、逻辑运算
    目录一、数据类型1、数据类型之布尔值:bool2、数据类型之元组:tuple列表和元组的区别3、数据类型之集合:set二、与用户交互1、获取用户输入2、输出内部信息扩展:python2与pyth......