Java并发编程之-了解CyclicBarrier

起因:一道面试题,关于concurrent包下的CyclicBarrier并发工具类,提出的一个情景题,因为不了解,所以花了一天的时间去学习并以此记录而诞生的这篇博客。

题目:假设有5个运动员(线程),让他们就绪在同一位置开始比赛跑步,当裁判(主线程)发出枪响号令。5个运动员(5个线程执行)开始奔跑,当5个线程跑到终点后。裁判(主线程执行)宣布比赛结果。

知识点:CyclicBarrier,CountDownLatch这两个位于JDK concurren包下的两个类。今天只实现CyclicBarrier这个类

原理:        CyclicBarrier大致是可循环利用的屏障,顾名思义,这个名字也将这个类的特点给明确地表示出来了。首先,便是可重复利用,说明该类创建的对象可以复用;其次,屏障则体现了该类的原理:每个线程执行时,都会碰到一个屏障,直到所有线程执行结束,然后屏障便会打开,使所有线程继续往下执行。

这里介绍CyclicBarrier的两个构造函数:CyclicBarrier(int parties)和CyclicBarrier(int parties, Runnable barrierAction) :前者只需要声明需要拦截的线程数即可,而后者还需要定义一个等待所有线程到达屏障优先执行的Runnable对象。

实现原理:在CyclicBarrier的内部定义了一个Lock对象,每当一个线程调用await方法时,将拦截的线程数减1,然后判断剩余拦截数是否为初始值parties,如果不是,进入Lock对象的条件队列等待。如果是,执行barrierAction对象的Runnable方法,然后将锁的条件队列中的所有线程放入锁等待队列中,这些线程会依次的获取锁、释放锁。

难点:

  1 :5个子线程执行运行完毕后,主线程执行其他任务方法,期间不能死亡。

  2:个人尝试使用线程池,来管理线程的执行。发现使用线程池子线程执行任务时,主线程会随时挂掉,这里我使用的睡眠sleep,但是我的“小伙伴“说这样不太好,这个问题暂时遗留记录

线程池版实现:

 1 import java.util.concurrent.*;
 2
 3 /**
 4 * Java并发编程之,了解CyclicBarrier
 5 *
 6 * @Author: Mr.Tk
 7 * @Date: 2019-03-10 15:39
 8 */
 9 public class CyclicBarrierDemo {
10
11     //创建一个线程池
12     private static final ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5,10,60, TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>());
13
14     //当拦截线程数量到达5,优先执行barrierAction参数线程方法,其次执行被拦截线程
15     private static final CyclicBarrier cyclicBarrier = new CyclicBarrier(5,new Runnable(){
16         @Override
17         public void run() {
18             System.out.println("裁判:预备... 跑!啾啪...枪声响起");
19         }
20     });
21
22     private static class TestThread extends Thread {
23
24         private String  name ;
25
26         public TestThread(String name){
27             this.name=name;
28         }
29
30         @Override
31         public void run() {
32             System.out.println("各就各位:"+name);
33             try {
34                 Thread.sleep(1000);
35                 //拦截线程
36                 cyclicBarrier.await();
37                 Thread.sleep(1000);
38                 System.out.println("到达终点:"+name);
39             } catch (InterruptedException e) {
40                 e.printStackTrace();
41             } catch (BrokenBarrierException e) {
42                 e.printStackTrace();
43             }
44         }
45     }
46
47     public static void main(String[] args) {
48         String[] str = {"运动员1","运动员2","运动员3","运动员4","运动员5"};
49         for (int i=0 ; i<5 ;i++){
50             //调用线程
51             threadPool.execute(new TestThread(str[i]));
52
53         }
54         try {
55             Thread.sleep(3000);//str.length*1000
56             System.out.println("裁判宣布成绩...hello world............");
57         } catch (InterruptedException e) {
58             e.printStackTrace();
59         }
60
61
62     }
63 }

"小伙伴"code非线程池版

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
* 非线程池操作
*
* @Author: Mr.Tk
* @Date: 2019-03-10 17:19
*/
public class CyclicBarrierDemo2 implements Runnable{

    //封装私有并发工具
    private CyclicBarrier cyclicBarrier;

    public CyclicBarrierDemo2(CyclicBarrier cyclicBarrier) {
        this.cyclicBarrier = cyclicBarrier;
    }

    @Override
    public void run() {
        try {
            System.out.println("ready");
            Thread.sleep(1000);
            cyclicBarrier.await();
            System.out.println("结束");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        //线程就绪5个后执行,线程方法run
        CyclicBarrierDemo2 cyclicBarrier = new CyclicBarrierDemo2(new CyclicBarrier(5, new Runnable() {
            @Override
            public void run() {
                System.out.println("裁判:预备... 跑!啾啪...枪声响起");
            }
        }));
        Thread thread1 = new Thread(cyclicBarrier);
        Thread thread2 = new Thread(cyclicBarrier);
        Thread thread3 = new Thread(cyclicBarrier);
        Thread thread4 = new Thread(cyclicBarrier);
        Thread thread5 = new Thread(cyclicBarrier);
        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
        thread5.start();

        //子线程执行完毕让每个子线程加入到主线程中。最后主线继续运行下去
        thread1.join();
        thread5.join();
        thread2.join();
        thread3.join();
        thread4.join();

        System.out.println("主线程执行完毕死亡,hello world ...");

    }

}

总结:从上代码看出,线程池的sleep方法暂时解决的主线程在自线程执行结束后,可以继续运行。但是就数据量大的处理来看,我门无法管理睡眠时间的长短。不能确定准确的睡眠时间所以存在风险。

  其二,如果我门不使用线程池来管理线程,面临的是内存性能的消耗,对于系统来说也是一笔开销。Condition这个锁对象是“小伙伴”提供给我的思路,暂时没有深入问题暂时遗留,有了解的可以私信讨论。

  个人设想:使用线程池管理线程时,将主线程挂起,将每个执行完毕的子线程(getCurrentThread()当前线程)执行等待方法(wait()),之后使用notifyAll()方法再将线程唤醒到主线程继续执行,这里又涉及到主线程等待后,子线程也全班等待后,谁将唤醒主线程的问题?如果让最后一个挂起线程唤醒主线程,具体怎么确定哪一个线程是执行到最后的?问题遗留。。。ing

注:不过就目前来看,该面试题是解决了... 之后会继续深入了解

原文地址:https://www.cnblogs.com/yuxiaoming/p/10506559.html

时间: 2024-10-07 09:37:34

Java并发编程之-了解CyclicBarrier的相关文章

Java 并发编程中的 CyclicBarrier 用于一组线程互相等待

Java 5 引入的 Concurrent 并发库软件包中的 CyclicBarrier 是一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point).在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用.因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier.CyclicBarrier 支持一个可选的 Runnable 命令,在一组线程中的最后一个线程到达之后(但在

Java并发编程之栅栏(CyclicBarrier)详解

栅栏类似闭锁,但是它们是有区别的. 闭锁用来等待事件,而栅栏用于等待其他线程.什么意思呢?就是说闭锁用来等待的事件就是countDown事件,只有该countDown事件执行后所有之前在等待的线程才有可能继续执行;而栅栏没有类似countDown事件控制线程的执行,只有线程的await方法能控制等待的线程执行. CyclicBarrier强调的是n个线程,大家相互等待,只要有一个没完成,所有人都得等着. 场景分析:10个人去春游,规定达到一个地点后才能继续前行.代码如下 import java.

java并发编程中CountDownLatch和CyclicBarrier的使用

转自:http://blog.csdn.net/hbzyaxiu520/article/details/6183714 在多线程程序设计中,经常会遇到一个线程等待一个或多个线程的场景,遇到这样的场景应该如何解决? 如果是一个线程等待一个线程,则可以通过await()和notify()来实现: 如果是一个线程等待多个线程,则就可以使用CountDownLatch和CyclicBarrier来实现比较好的控制. 下面来详细描述下CountDownLatch的应用场景: 例如:百米赛跑:8名运动员同时

【Java并发编程实战】—–“J.U.C”:CyclicBarrier

在上篇博客([Java并发编程实战]-–"J.U.C":Semaphore)中,LZ介绍了Semaphore,下面LZ介绍CyclicBarrier.在JDK API中是这么介绍的: 一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point).在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用.因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier. Cy

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

下面对上面说的三个辅助类进行一个总结: 1)CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点不同: CountDownLatch一般用于某个线程A等待若干个其他线程执行完任务之后,它才执行: 而CyclicBarrier一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行: 另外,CountDownLatch是不能够重用的,而CyclicBarrier是可以重用的. 2)Semaphore其实和锁有点类似,它一般用于控制对某组资源的访问权

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

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

Java并发编程笔记 并发概览

并发概览 >>同步 如何同步多个线程对共享资源的访问是多线程编程中最基本的问题之一.当多个线程并发访问共享数据时会出现数据处于计算中间状态或者不一致的问题,从而影响到程序的正确运行.我们通常把这种情况叫做竞争条件(race condition),把并发访问共享数据的代码叫做关键区域(critical section).同步就是使得多个线程顺序进入关键区域从而避免竞争条件的发生. >>线程安全性 编写线程安全的代码的核心是要对状态访问操作进行管理,尤其是对共享的和可变的状态访问. 线

JAVA并发编程J.U.C学习总结

前言 学习了一段时间J.U.C,打算做个小结,个人感觉总结还是非常重要,要不然总感觉知识点零零散散的. 有错误也欢迎指正,大家共同进步: 另外,转载请注明链接,写篇文章不容易啊,http://www.cnblogs.com/chenpi/p/5614290.html 本文目录如下,基本上涵盖了J.U.C的主要内容: JSR 166及J.U.C Executor框架(线程池. Callable .Future) AbstractQueuedSynchronizer(AQS框架) Locks & C

【Java并发编程】并发编程大合集-值得收藏

http://blog.csdn.net/ns_code/article/details/17539599这个博主的关于java并发编程系列很不错,值得收藏. 为了方便各位网友学习以及方便自己复习之用,将Java并发编程系列内容系列内容按照由浅入深的学习顺序总结如下,点击相应的标题即可跳转到对应的文章    [Java并发编程]实现多线程的两种方法    [Java并发编程]线程的中断    [Java并发编程]正确挂起.恢复.终止线程    [Java并发编程]守护线程和线程阻塞    [Ja