java并发编程学习11--同步器--栅栏

算法霜晶客
• 阅读 1850

【同步器

java.util.concurrent包包含几个能帮助人们管理相互合作的线程集的类。这些机制具有为线程直间的共用集结点模式提供的‘预制功能’。如果有一个相互合作的线程满足这些行为模式之一,那么应该直接使用提供的类库而不是显示的使用锁与条件的集合。

【栅栏

CyclicBarrier类实现了一个集结点(rendezvous)称为栅栏(barrier)。考虑大量线程运行在一次计算的不同部分的情形。当所有部分都准备好时,需要把结果组合到一起。当一个线程完成了它那部分的任务后,我们让他运行到栅栏处。一旦所有的线程都到达了这个栅栏,栅栏就撤销,线程可以继续运行。如果任何一个线程在栅栏上等待时离开,那么栅栏就被破坏掉(线程离开可能时等待超时)。这种情况下,其他所有线程await方法上抛出BrokenBarrierException异常。那些已经在等待的线程立即中止await的调用。可以提供一个可选的栅栏动作,当所有线程到达栅栏时,就会执行这个动作。

Runnable barrierAction = ...
CyclicBarrier barrire = new CyclicBarrier(nthreads,barrierAction);

栅栏被称为时循环的,以为可以在所有等待的线程被释放后重用(这里与倒计时门闩不同,倒计时门闩只能使用一次)。

【常用方法

  • public int await() throws InterruptedException,BrokenBarrierException:
    在所有参与者都已经在此 barrier 上调用 await方法之前,将一直等待。如果当前线程不是将到达的最后一个线程,出于调度目的,将禁用它,且在发生以下情况之一前,该线程将一直处于休眠状态:

      - 最后一个线程到达;或者
      - 其他某个线程中断当前线程;或者
      - 其他某个线程中断另一个等待线程;或者
      - 其他某个线程在等待 barrier 时超时;或者
      - 其他某个线程在此 barrier 上调用 reset()。
      

如果当前线程在进入此方法时已经设置了该线程的中断状态;或者在等待时被中断则InterruptedException,并且清除当前线程的已中断状态。

  • 如果在线程处于等待状态时 barrier 被 reset(),或者在调用 await 时 barrier 被损坏,抑或任意一个线程正处于等待状态,则抛出 BrokenBarrierException 异常。
  • 如果任何线程在等待时被 中断,则其他所有等待线程都将抛出 BrokenBarrierException 异常,并将 barrier 置于损坏状态。
  • 如果当前线程是最后一个将要到达的线程,并且构造方法中提供了一个非空的屏障操作,则在允许其他线程继续运行之前,当前线程将运行该操作。
  • 如果在执行屏障操作过程中发生异常,则该异常将传播到当前线程中,并将 barrier 置于损坏状态。
    返回:到达的当前线程的索引,其中,索引 getParties() - 1 指示将到达的第一个线程,零指示最后一个到达的线程.

抛出:

  • InterruptedException - 如果当前线程在等待时被中断
  • BrokenBarrierException - 如果另一个 线程在当前线程等待时被中断或超时,或者重置了 barrier,或者在调用 await 时 barrier 被损坏,抑或由于异常而导致屏障操作(如果存在)失败。

【例子

1.应用程序启动前,所有子线程准备工作完成,不需要返回值

public class Application{

    public static void main(String[] args) throws IOException, InterruptedException {
        //需要三个子线程准备
        CyclicBarrier barrier = new CyclicBarrier(3);
        //如果初始化barrier的线程数,与实际子线程数不同,barrier将会一直等待
        ExecutorService executor = Executors.newFixedThreadPool(3);
        executor.submit(new Thread(new InitThread(barrier, "子线程1")));
        executor.submit(new Thread(new InitThread(barrier, "子线程2")));
        executor.submit(new Thread(new InitThread(barrier, "子线程3")));

        executor.shutdown();
    }
}

class InitThread implements Runnable {
    // 一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)
    private CyclicBarrier barrier;
    private String name;

    public InitThread(CyclicBarrier barrier, String name) {
        this.barrier = barrier;
        this.name = name;
    }
    @Override
    public void run() {
        try {
            Thread.sleep(1000 * (new Random()).nextInt(8));
            System.out.println(name + " 初始化完成...");
            barrier.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
        System.out.println(name + " 开始运行!");
    }
}

2.应用程序启动前,所有子线程准备工作完成,需要返回值汇总

public class ApplicationNeedReturn {

    public static void main(String[] args) throws IOException, InterruptedException, ExecutionException {
        //需要三个子线程准备
        CyclicBarrier barrier = new CyclicBarrier(3);
        //如果初始化barrier的线程数,与实际子线程数不同,barrier将会一直等待
        ExecutorService executor = Executors.newFixedThreadPool(3);
        FutureTask<Long> time1 = new FutureTask<Long>(new InitThread2(barrier, "子线程1"));
        FutureTask<Long> time2 = new FutureTask<Long>(new InitThread2(barrier, "子线程2"));
        FutureTask<Long> time3 = new FutureTask<Long>(new InitThread2(barrier, "子线程3"));
        executor.submit(time1);
        executor.submit(time2);
        executor.submit(time3);
        long total = time1.get() + time2.get() + time3.get();
        System.out.println("准备完成,耗时:" + total);
        executor.shutdown();
    }
}

class InitThread2 implements Callable<Long> {

    private CyclicBarrier barrier;
    private String name;
    public InitThread2(CyclicBarrier barrier, String name) {
        this.barrier = barrier;
        this.name = name;
    }

    @Override
    public Long call() {
        long time = 1000 * (new Random()).nextInt(8);
        try {
            Thread.sleep(time);
            System.out.println(name + " 初始化完成... : " + time) ;
            barrier.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
        return time;
    }
}
点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
3年前
java多线程学习
   Java1.5提供了一个非常高效实用的多线程包:java.util.concurrent,提供了大量高级工具,可以帮助开发者编写高效、易维护、结构清晰的Java多线程程序。从这篇blog起,我将跟大家一起共同学习这些新的Java多线程构件1\.CountDownLatch   我们先来学习一下JDK1.5API中关于这个类的
Wesley13 Wesley13
3年前
Java多线程并发控制工具CountDownLatch,实现原理及案例
闭锁(CountDownLatch)是Java多线程并发中的一种同步器,它是JDK内置的同步器。通过它可以定义一个倒计数器,当倒计数器的值大于0时,所有调用await方法的线程都会等待。而调用countDown方法则可以让倒计数器的值减一,当倒计数器值为0时所有等待的线程都将继续往下执行。闭锁的主要应用场景是让某个或某些线程在某个运行节点上等待N个条件都
Stella981 Stella981
3年前
Executor框架
任务是一组逻辑工作单元,而线程则是使任务异步执行的机制。线程池简化了线程的管理工作,并且java.util.concurrent提供了一种灵活的线程池实现作为Executor框架的一部分。在Java类库中,任务执行的主要抽象不是Thread,而是Executor,如下所示:publicinterfaceExecutor{void
Wesley13 Wesley13
3年前
Java中的ReentrantLock和synchronized两种锁定机制的对比
多线程和并发性并不是什么新内容,但是Java语言设计中的创新之一就是,它是第一个直接把跨平台线程模型和正规的内存模型集成到语言中的主流语言。核心类库包含一个 Thread 类,可以用它来构建、启动和操纵线程,Java语言包括了跨线程传达并发性约束的构造—— synchronized 和 volatile 。在简化与平台无关的并发类的开发的
Stella981 Stella981
3年前
ReetrantLock源码分析
ReentrantLock类的大部分逻辑,都是其均继承自AQS的内部类Sync实现的啥是AQS:Java并发编程核心在于java.concurrent.util包而juc当中的大多数同步器实现都是围绕着共同的基础行为,比如「等待队列、条件队列、独占获取、共享获取」等,而这个行为的抽象就是基于AbstractQueuedSynchron
Wesley13 Wesley13
3年前
JUC
Java5.0在java.util.concurrent包中提供了多种并发容器类来改进同步容器的性能。CountDownLatch一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一
Wesley13 Wesley13
3年前
Java并发中常用同步工具类
同步工具类可以是任何一个对象,只要它根据其自身的状态来协调线程控制流。阻塞队列(BlockingQueue)可以作为同步工具类,其他类型的同步工具类还包括信号量(Semaphore),栅栏(Barrier)以及闭锁(Latch)。在平台类库中还包含其他一些同步工具类的类,如果这些类还无法满足需要,那么可以创建自己的同步工具类。闭锁Latch
Stella981 Stella981
3年前
Linux 多线程
I.同步机制线程间的同步机制主要包括三个:互斥锁:以排他的方式,防止共享资源被并发访问;互斥锁为二元变量,状态为0开锁、1上锁;开锁必须由上锁的线程执行,不受其它线程干扰.条件变量:
Wesley13 Wesley13
3年前
Java并发编程指南
  多线程是实现并发机制的一种有效手段。在Java中实现多线程有两种手段,一种是继承Thread类,另一种就是实现Runnable/Callable接口。  java.util.concurrent包是专为Java并发编程而设计的包。类图如下:!(https://oscimg.oschina.net/oscnet/29ddbb
Wesley13 Wesley13
3年前
Java集合框架一览笔录
1、集合概念集合类主要负责保存、盛装其他数据,因此集合类也被称为容器类。所以的集合类都位于java.util包下,后来为了处理多线程环境下的并发安全问题,java5还在java.util.concurrent包下提供了一些多线程支持的集合类。集合分为两大类:Collection、Map。Collection(集合),每个元素存储单个