java中的JUC组件(Semaphore、CountDownLatch、CyclicBarrier)

目录

  • 1、简介
  • 2、Semaphore
  • 3、CountDownLatch
  • 4、CyclicBarrier

1、简介

Semaphore、CountDownLatch、CyclicBarrier 这三个工具类都是用于并发控制的操作,底层都是基于AQS去实现的;

  • Semaphore(信号量): 提供一个竞争资源处理的工具,当系统内有足够的信号量事,线程可以去获取信号量执行操作,当信号量资源被使用完后,需要等待资源释放后后续线程(资源竞争)才能够执行;
  • CountDownLatch(闭锁):可以理解为一个开关,闭锁创建的时候,可以指定一个闭锁打开依赖条件个数,只有满足条件的资源就绪时,闭锁打开,对应的线程可以执行后续任务;
  • CyclicBarrier(栅栏):当所有依赖栅栏的线程执行到关键节点的时候,都需要等待其他线程到达栅栏点,否则无法继续执行,所有线程到达栅栏的关键点,这些线程即可继续执行后续任务。

2、Semaphore

semaphore在代码中使用的执行流程简图:

其本质就是操作系统的P-V操作,当资源足够的时候线程获得资源并执行,资源不足时线程等待或者退出,当资源被释放时线程又可以获取竞争资源继续执行;

2.1、源码实现:

Semaphore类的代码结构如上图,可以看到其内部实现了公平锁和非公平锁,所以我们可以使用这两种不同的模式来构建Semaphore对象实例;

不论我们使用公平与非公平锁,其初始化最终都会调用到sync的构造方法;
下面可以看看内部的获取资源以及释放资源的具体实现:


public class Semaphore implements java.io.Serializable {
    abstract static class Sync extends AbstractQueuedSynchronizer{
        //初始化
        Sync(int permits) {
            setState(permits);
        }
    }
    public void acquire(int permits) throws InterruptedException {
        if (permits < 0) throw new IllegalArgumentException();
        sync.acquireSharedInterruptibly(permits);
    }
    public void release() {
        sync.releaseShared(1);
    }
}

sync.acquireSharedInterruptibly(permits) 最终会调用的AQS的实现,对于AQS中该实现简单说明:如果这里能够获取到资源,内部就返回success,这里会扣减permits的值,任务继续执行,否则,将当前线程加入等待队列中(具体参考AbstractQueuedSynchronizer.acquireSharedInterruptibly());

3、CountDownLatch

CountDownLatch在代码中使用的执行流程简图:

3.1、源码实现

public class CountDownLatch {

    private static final class Sync extends AbstractQueuedSynchronizer {
        protected int tryAcquireShared(int acquires) {
            return (getState() == 0) ? 1 : -1;
        }
    }

    public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }

    public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

    public void countDown() {
        sync.releaseShared(1);
    }
}

当某个线程调用await()方法时由于CountDownLatch.Sync中的实现tryAcquireShared会判断state是否等于0,如果不等于,就会进入等待队列,直到countDown调用sync.releaseShared(1)使得sync的状态到0,await的线程才会继续执行;

4、CyclicBarrier

CyclicBarrier在代码中使用的执行流程简图:

4.1、源码实现

public class CyclicBarrier {

    public int await() throws InterruptedException, BrokenBarrierException {
        try {
            return dowait(false, 0L);
        } catch (TimeoutException toe) {
            throw new Error(toe); // cannot happen
        }
    }
    private static class Generation {
        boolean broken = false;
    }
    private int dowait(boolean timed, long nanos)
        throws InterruptedException, BrokenBarrierException,
               TimeoutException {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            //保存当前generation 副本
            final Generation g = generation;
            //如果当前副本已推出,抛出异常
            if (g.broken)
                throw new BrokenBarrierException();
            //如果当前线程已中断抛出异常
            if (Thread.interrupted()) {
                breakBarrier();
                throw new InterruptedException();
            }

            //计算当前是否所有线程到达“栅栏”
            int index = --count;
            if (index == 0) {  // tripped
                //所有线程到达栅栏
                boolean ranAction = false;
                try {
                    //如果初始化了自定方法,触发
                    final Runnable command = barrierCommand;
                    if (command != null)
                        command.run();
                    ranAction = true;
                    //唤醒所有到达“栅栏”的线程,并跳到下一个新的generation
                    nextGeneration();
                    return 0;
                } finally {
                    if (!ranAction)
                        breakBarrier();
                }
            }

            // loop until tripped, broken, interrupted, or timed out
            //如果还有线程没有到达栅栏
            for (;;) {
                try {
                    //根据设置的等待时间进行等待
                    //里面会调用LockSupport.park(this);
                    //将当前线程放入等待队列中
                    if (!timed)
                        trip.await();
                    else if (nanos > 0L)
                        nanos = trip.awaitNanos(nanos);
                } catch (InterruptedException ie) {
                    //异常处理流程
                    if (g == generation && ! g.broken) {
                        breakBarrier();
                        throw ie;
                    } else {
                        // We're about to finish waiting even if we had not
                        // been interrupted, so this interrupt is deemed to
                        // "belong" to subsequent execution.
                        Thread.currentThread().interrupt();
                    }
                }

                if (g.broken)
                    throw new BrokenBarrierException();
                //当前线程geration 不等于实际 geration 正常返回
                if (g != generation)
                    return index;
                //超过等待时间所有线程还未到达“栅栏”,抛出异常
                if (timed && nanos <= 0L) {
                    breakBarrier();
                    throw new TimeoutException();
                }
            }
        } finally {
            lock.unlock();
        }
    }
    //跳到下一个geration操作
    private void nextGeneration() {
        // signal completion of last generation
        trip.signalAll();
        // set up next generation
        count = parties;
        generation = new Generation();
    }
}

CyclicBarrier 维护了一个计数器,和一个 geration 每次调用await都会有将计数器减一,并且产生一个新的 geration ,只要计数器不为零,所有前置线程都会触发 ((Condition)trip).await(); 内部会调用 LockSupport.park(this); 方法将线程加入等待队列,知道所有线程就绪,会调用 trip.signalAll(); 唤醒所有线程,同时执行一个用户自定义的 Runnable 策略

原文地址:https://www.cnblogs.com/wykCN/p/12153785.html

时间: 2024-10-17 22:10:16

java中的JUC组件(Semaphore、CountDownLatch、CyclicBarrier)的相关文章

Java学习笔记--并发工具Semaphore,CountDownLatch,CyclicBarrier,Exchanger

Semaphore 实现典型的信号量 CountDownLatch 在指定数量的事件发生前一直等待 CyclicBarrier 使一组线程在一个预定义的执行点等待 Exchanger 交换两个线程的数据 1. Semaphore 信号量(Semaphore),是在多线程环境下使用的一种设施, 它负责协调各个线程, 以保证它们能够正确.合理的使用公共资源 在java中,还可以设置该信号量是否采用公平模式,如果以公平方式执行,则线程将会按到达的顺序(FIFO)执行,如果是非公平,则可以后请求的有可能

Java多线程系列--“JUC锁”10之 CyclicBarrier原理和示例

概要 本章介绍JUC包中的CyclicBarrier锁.内容包括:CyclicBarrier简介CyclicBarrier数据结构CyclicBarrier源码分析(基于JDK1.7.0_40)CyclicBarrier示例 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3533995.html CyclicBarrier简介 CyclicBarrier是一个同步辅助类,允许一组线程互相等待,直到到达某个公共屏障点 (common barrier p

java中的日志组件-log4j

1.为什么使用日志组件 Log4J是Apache的一个开放源代码项目,它是一个日志操作包,通过使用Log4J,可以指定日志信息输出的目的地,如控制台.文件.CUI组件.NT的事件记录器:还可以控制每一条日志输出格式.此外,通过定义日志信息的级别,能够非常细致地控制日志的输出,最令人感兴趣的是,这些功能可以通过一个配置文件来灵活进行配置,而不需要修改应程序代码. 在应用程序中输出日志有3个目的: 监视代码中变量的变化情况,把数据周期性记录到文件中供其他应用进行统计分析工作: 跟踪代码运行时轨迹,作

java中的一些组件

文件的上传下载:common fileupload  (文件大小<做缓存>,文件转码,文件类型,) excel,word,pdf导出:poi xml解析:DOM4J 邮件:commons,email 验证码:captcha 拼音解析:pinyin4J 定时任务:quartz orm框架:hibernate,ibatis mvc:Struts2,springmvc4 使用strusts2.x 1导入jar包 2配置web.xml中配置Struts2中央控制器(过滤器) 3创建struts.xml

JAVA中按钮的事件监听的三种方式

JAVA中的Swing组件,按钮的重点是进行事件的监听,可以通过调用JButton的addActionListener()方法.这个方法接受一个实现ActionListener接口的对象作为参数,ActionListener接口中只包含一个actionPerformed()方法,所以如果想把事件处理的代码与JButton进行关联,就需要如下的三种做法: 第一种: public class Button extends MyFrame {    private JButton        b1

Java并发编程小总结:CountDownLatch、CyclicBarrier和Semaphore

Java并发编程小总结:CountDownLatch.CyclicBarrier和Semaphore这几个类都是在JUC下,也就是java.util.concurrent包下.这两天学习了一下并发编程中的三个类的使用和一些应用场景,所以做一下记录和总结,方便自己日后再查看复现. 1.CountDownLatch.这个类的核心思想总结为8个字“秦灭6国,一统华夏”.它可以实现的是一个类似计数器的功能,与CyclicBarrier的思想正好相反.是一个减法操作.CountDownLatch有且只有一

java并发之CountDownLatch、Semaphore和CyclicBarrier

JAVA并发包中有三个类用于同步一批线程的行为,分别是CountDownLatch.Semaphore和CyclicBarrier. CountDownLatch CountDownLatch是一个计数器闭锁,主要的功能就是通过await()方法来阻塞住当前线程,然后等待计数器减少到0了,再唤起这些线程继续执行. 这个类里主要有两个方法,一个是向下减计数器的方法:countdown(),其实现的核心代码如下: public boolean tryReleaseShared(int release

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

JAVA并发包中有三个类用于同步一批线程的行为,分别是CountDownLatch.Semaphore和CyclicBarrier. CountDownLatch CountDownLatch是一个计数器闭锁,主要的功能就是通过await()方法来阻塞住当前线程,然后等待计数器减少到0了,再唤起这些线程继续执行. 这个类里主要有两个方法,一个是向下减计数器的方法:countdown(),其实现的核心代码如下: public boolean tryReleaseShared(int release

CountDownLatch/CyclicBarrier/Semaphore 使用过吗?

CountDownLatch/CyclicBarrier/Semaphore 使用过吗?下面详细介绍用法: 一,CountDownLatch  背景; countDownLatch(同步援助)是在java1.5被引入,跟它一起被引入的工具类还有CyclicBarrier(同步援助).Semaphore(计数信号量).concurrentHashMap和BlockingQueue(阻塞队列). 存在于java.util.cucurrent包下.   概念理解: 让一些线程阻塞,直到另外一些线程完成