`
suichangkele
  • 浏览: 200384 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

juc - CyclicBarrier源码解读

    博客分类:
  • java
阅读更多

之前看了CountDownLatch,他的实现是使用了aqs,提前设置好state的值,如果state不是0的时候调用await就会阻塞当前线程,加入到aqs的队列中,调用countDown就会减小state的值,当state的值时0的时候就会释放锁,将队列中的所有的线程释放,开始运行。这个CountDownLatch可以用于不同种类的线程之间,比如我们在连zk的时候,因为zkClient内部是使用的另一个线程链接zk,我们的主线程要在zk链接之后才能继续操作,所以就使用了CountDownLatch,这是用在不同种类的线程中。CountDownLatch也可以用在相同种类的线程中,比如有这么一个需求:要去一个饭店开一个生日宴会,这个宴会必须等待所有的朋友来了才可以一起开始,这个时候可以使用下面的代码:

public static void main(String[] args) {
		
		final CountDownLatch latch = new CountDownLatch(10);
		
		for(int i=0;i<10;i++){
			new Thread(new Runnable() {
				
				public void run() {
					System.out.println(Thread.currentThread().getName() + " 已经来到了。");//一个线程来了,代表一个顾客
					latch.countDown();//表示又来了一个人
					try {
						latch.await();//当前的人等待其他人来
						System.out.println("既然都来了,就开始吧");//当所有的人都来了,则开始
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}).start();
		}
	}
	

 上面的代码中,CountDownLatch是用在同种类的线程中,表示所有的线程在都达到某个状态后才会执行下一个步骤。在jdk中有一个更加好用的类,可以提供类似的作用,并且更简单,即CyclicBarrier类。CyclicBarrier类表示一个阻碍,在构造这个类时就要穿入一个值,表示标记的大小。在条件不满足时,所有调用await的线程都会被挂起,同时将一个标记减一,再将标记变为0之后,就会将所有阻塞的线程变为可以执行的。我们看一下他的源码:

1、构造方法:

public CyclicBarrier(int parties, Runnable barrierAction) {//parties表示要满足的调用await的个数,也就是上面说的要进行的聚会至少要来的人的个数。第二个参数是个可以执行的runnable,表示当条件满足之后(也就是partie变为0之后),要做的一件事,由最后触发await的线程执行。
    if (parties <= 0) throw new IllegalArgumentException();
    this.parties = parties;//这个是不变的,供 一个方法返回。
    this.count = parties;//这个count是会不断减小的,每调用一次awati就会减一。
    this.barrierCommand = barrierAction;//条件满足后要执行的任务
}

这个类中还有好多属性,

    ReentrantLock lock :用于在调用await的时候加锁,防止并发修改count的值造成不准确。

     Condition trip:从上面的lock中产生的condition,用于在不满足条件时将调用await的线程放到等待的队列中,当条件满足后将所有的等待的移动到lock(内部是aqs)的队列中。

     Generation generation:这个属性狠简单,因为CyclicBarrier是一个可以重复使用的barrier,这个generation表示第几次使用,每当parties变为0之后这一代就算完了,再进行下一代的操作。它里面封装了一个boolean属性,表示当前的这一代有没有被破坏。当某个被阻塞的线程被调用interrupt之后就会变为true,即当前的一代被破坏了。

 

2、await方法

public int await() throws InterruptedException, BrokenBarrierException {
   try {
       return dowait(false, 0L);//从await中调用的是没有等待时间限制的dowait
   } catch (TimeoutException toe) {
       throw new Error(toe); // cannot happen;
   }
}

 第一个参数表示是否有时间限制,第二个参数是如果有时间限制的话,限制的时间

  private int dowait(boolean timed, long nanos)
        throws InterruptedException, BrokenBarrierException,
               TimeoutException {
        final ReentrantLock lock = this.lock;
        lock.lock();//因为里面要修改count,所以加锁,防止并发修改
        try {
           final Generation g = generation;
           if (g.broken)
               throw new BrokenBarrierException();//关于broken的我没有研究,所以不再对broken的情况进行注释。

           if (Thread.interrupted()) {
               breakBarrier();
               throw new InterruptedException();
           }
           int index = --count;//减小count,
           if (index == 0) {  // 刚上来不会是0的,这个是等到指定的次数被调用之后触发
               boolean ranAction = false;
               try {
                   final Runnable command = barrierCommand;//要执行的任务
                   if (command != null)
                       command.run();//由最后调用await的线程调用,注意这里在执行run的时候可能会抛异常,就会进入finally的beakBarrier方法,其他线程在重新执行后就会全部抛出BrokenBarrierException异常。
                   ranAction = true;
                   nextGeneration();//开启下一代,操作包括:1、将count重新设置为parties,2、更新generation的值,3、将全部condtion中阻塞的线程释放
                   return 0;
               } finally {
                   if (!ranAction)
                       breakBarrier();
               }
           }

            // loop until tripped, broken, interrupted, or timed out
            for (;;) {//这个是当await没有调用指定的次数时
                try {
                    if (!timed)//如果没有时间限制,则调用condtion.await,也就是放入到conditon的队列中,将线程挂起
                        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)//如果因为某个原因导致broken,则所有唤醒之后的线程都会抛出异常
                    throw new BrokenBarrierException();

                if (g != generation)
                    return index;

                if (timed && nanos <= 0L) {//如果是有时间限制的,如果等待超时候就会抛异常。
                    breakBarrier();//这个方法会将generation设置为broken,然后将condition中阻塞的线程全部释放。
                    throw new TimeoutException();
                }
            }
        } finally {
            lock.unlock();
        }
    }

 

在不考虑barrierBroken的前提下,这个类还是很容易看懂的。

 

 

 

 

 

 

 

 

 

 

 

 

分享到:
评论

相关推荐

    tuling-juc-final.zip

    本项目"tuling-juc-final.zip"显然聚焦于Java并发编程的实践,通过一系列代码示例来演示和解释Java内存模型(JMM)、`synchronized`关键字以及`volatile`关键字的使用。下面我们将深入探讨这些核心概念。 Java内存...

    Java-JUC-多线程 进阶

    Java-JUC-多线程进阶 Java-JUC-多线程进阶resources是 Java 并发编程的高级课程,涵盖了 Java 中的并发编程概念、线程安全、锁机制、集合类、线程池、函数式接口、Stream流式计算等多个方面。 什么是JUC JUC...

    个人学习-JUC-笔记

    - **CountDownLatch/CyclicBarrier/Semaphore**:信号量类,用于控制并发线程数量或同步点。 8. **FutureTask** - **FutureTask**:表示一个异步计算的结果,它可以被取消,查询是否完成,获取或检查结果。 9. *...

    heima-JUC-资料

    8. **线程通信**:`Semaphore`(信号量)、`CountDownLatch`(倒计时器)、`CyclicBarrier`(循环栅栏)和`Phaser`(屏障)等工具类,用于控制线程间的同步和通信,实现特定的并发模式。 9. **Fork/Join框架**:...

    Java 多线程与并发(7-26)-JUC - 类汇总和学习指南.pdf

    "Java 多线程与并发(7-26)-JUC - 类汇总和学习指南" Java 多线程与并发是 Java 编程语言中的一部分,用于处理多线程和并发编程。Java 提供了一个名为 JUC(Java Utilities for Concurrency)的框架,用于帮助开发者...

    A-JUC-JVM-Java并发知识..pdf

    JUC的同步器包括CountDownLatch、CyclicBarrier、Semaphore等,它们是为了解决多个线程协作完成特定任务的工具。例如,CountDownLatch可以让一些线程等待其他线程完成操作后再继续执行,而CyclicBarrier则让一组线程...

    juc-study编程笔记.md

    学习狂神说的juc编程的笔记

    juc-jenkins-2018:JUC Jenkins 2018演示源代码

    juc-jenkins-2018 JUC Jenkins 2018演示源代码 先决条件 为了运行此演示,必须有一个有效的JDK,git命令以及curl。 克隆存储库 将此存储库克隆到您家中的某个位置: git clone ...

    juc-1(2).docx

    【JUC 概念】 Java Util Concurrency (JUC) 是 Java SDK 中的一个核心包,位于 `java.util.concurrent` 下,它提供了丰富的线程同步和并发工具类,旨在简化多线程编程,提高程序的并发性能。JUC 包含了线程池、并发...

    juc_nio_linux.rar

    Java并发编程库(Java Util Concurrency,简称JUC)是Java平台中用于高效并发处理的重要工具,它提供了线程池、锁、原子变量等高级并发工具。在Java中,`java.util.concurrent`包包含了大量并发控制和并行计算的类与...

    JUC-3 微程序控制计算机系列实验资源

    微程序控制器实验1. 连接好实验线路,检查无误后接通电源。2. 将编程开关(MJ20)置为PROM(编程)状态。3. 将STATE UNIT中的STEP置为“STEP”状态,STOP置为“RUN”状态。4. 在UA5-UA0开关上置要写的某个微地址(八进制)...

    juc-learn:juc相关源码的分析以及使用介绍

    本项目"juc-learn"专注于JUC相关源码的分析和使用介绍,旨在帮助开发者深入理解并熟练运用这些并发工具。 1. **并发基础** 在Java中,多线程是并发编程的基础。通过创建Thread对象或实现Runnable接口,我们可以...

    JUC-master

    《JUC:Java并发编程的艺术》 在Java世界中,JUC(Java Util Concurrency)是并发编程的核心库,它提供了丰富的...通过深入学习JUC-master项目,我们可以更深入地理解Java并发编程的原理和实践,提升我们的编程技能。

    juc-demo:JUC包下常用工具练习Demo

    juc-demo JUC包下常用工具练习Demo 内容: 1、Semaphore 2、CountDownLatch 3、CyclicBarrier 4、ReentrantLock + Condition实现阻塞队列 Created by @minghui.y.

    java并发编程专题(九)----(JUC)浅析CyclicBarrier

    Java 并发编程专题(九)----(JUC)浅析 CyclicBarrier CyclicBarrier 是 Java 并发编程中的一个同步辅助工具,它允许一组线程全部等待彼此到达公共屏障点。它的字面意思是可循环使用的屏障,用于让一组线程到达一...

    免费开源!!主要是Java技术栈的文章

    1、Java并发体系-第一阶段-多线程基础知识 2、Java并发体系-第二阶段-锁与同步-[1] 3、Java并发体系-第二阶段-锁与同步-[2] 4、Java并发体系-第二阶段-锁与同步-[3] ...7、Java并发体系-第四阶段-AQS源码解读-[1]

    JUC线程高级

    JUC线程高级,

    JUC并发编程与源码分析视频课.zip

    《JUC并发编程与源码分析视频课》是一门深入探讨Java并发编程的课程,主要聚焦于Java Util Concurrency(JUC)库的使用和源码解析。JUC是Java平台提供的一组高级并发工具包,它极大地简化了多线程编程,并提供了更...

    22 尚硅谷Java JUC线程高级视频

    教程视频:在 Java 5.0 提供了 java.util.concurrent(简称JUC)包,在此包中增加了在并发编程中很常用的工具类, 用于定义类似于线程的自定义子系统,包括线程池,异步 IO 和轻量级任务框架;还提供了设计用于多线程上下文...

    JUC+课程源码+线程操作

    本课程资源主要围绕JUC进行展开,通过样例源码帮助学习者深入理解和掌握线程操作的相关知识。 在JUC中,核心组件包括`ExecutorService`、`Semaphore`、`CountDownLatch`、`CyclicBarrier`、`Future`、`...

Global site tag (gtag.js) - Google Analytics