java并发编程之CyclicBarrier

一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。

CyclicBarrier 支持一个可选的 Runnable 命令,在一组线程中的最后一个线程到达之后(但在释放所有线程之前),该命令只在每个屏障点运行一次。若在继续所有参与线程之前更新共享状态,此屏障操作 很有用。

CountDownLatch : 一个线程(或者多个), 等待另外N个线程完成某个事情之后才能执行。 CyclicBarrier       : N个线程相互等待,任何一个线程完成之前,所有的线程都必须等待。

这样应该就清楚一点了,对于CountDownLatch来说,重点是那个“一个线程”, 是它在等待, 而另外那N的线程在把“某个事情”做完之后可以继续等待,可以终止。而对于CyclicBarrier来说,重点是那N个线程,他们之间任何一个没有完成,所有的线程都必须等待。

package com.lala.shop;

import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 *  这里演示了一个例子:五个人一同去买 衬衫、裤子、鞋子。
 *  所有人必须先全部买完衬衫,然后才能去买裤子,全部买完裤子之后,在去买鞋子,全部买完鞋子之后,事情执行完成
 */
public class CyclicBarrierDemo
{
	public static void main(String[] args)
	{
		CyclicBarrier cb = new CyclicBarrier(5, new Runnable(){
			public void run()
			{
				System.out.println("人已经到齐,准备下一步...");
			}
		});
		ExecutorService runner = Executors.newFixedThreadPool(5);
		runner.submit(new Shopping("李大嘴", cb));
		runner.submit(new Shopping("白展堂", cb));
		runner.submit(new Shopping("郭芙蓉", cb));
		runner.submit(new Shopping("佟湘玉", cb));
		runner.submit(new Shopping("吕秀才", cb));
		runner.shutdown();
	}
}

class Shopping implements Runnable
{
	private String user;
	private CyclicBarrier cb;

	public Shopping(String user, CyclicBarrier cb)
	{
		this.user = user;
		this.cb = cb;
	}

	public void run()
	{
		try
		{
			long shirtTime = getRandomTime();

			TimeUnit.SECONDS.sleep(shirtTime);

			System.out.println(user + "买完衬衫,花了时间:" + shirtTime);

			cb.await();

			long pantsTime = getRandomTime();

			TimeUnit.SECONDS.sleep(pantsTime);

			System.out.println(user + "买完裤子,花了时间:" + pantsTime);

			cb.await();

			long shoseTime = getRandomTime();

			TimeUnit.SECONDS.sleep(shoseTime);

			System.out.println(user + "买完鞋子,花了时间:" + shoseTime);

			cb.await();

			System.out.println(user + "东西已经买齐了,回家");

		} catch (InterruptedException | BrokenBarrierException e)
		{
			e.printStackTrace();
		}
	}

	private long getRandomTime()
	{
		return new Random().nextInt(9) + 1;
	}
}

输出结果为:

吕秀才买完衬衫,花了时间:1

白展堂买完衬衫,花了时间:1

佟湘玉买完衬衫,花了时间:3

李大嘴买完衬衫,花了时间:8

郭芙蓉买完衬衫,花了时间:9

人已经到齐,准备下一步...

白展堂买完裤子,花了时间:4

佟湘玉买完裤子,花了时间:4

吕秀才买完裤子,花了时间:5

郭芙蓉买完裤子,花了时间:8

李大嘴买完裤子,花了时间:9

人已经到齐,准备下一步...

吕秀才买完鞋子,花了时间:1

白展堂买完鞋子,花了时间:2

佟湘玉买完鞋子,花了时间:7

郭芙蓉买完鞋子,花了时间:8

李大嘴买完鞋子,花了时间:8

人已经到齐,准备下一步...

李大嘴东西已经买齐了,回家

吕秀才东西已经买齐了,回家

白展堂东西已经买齐了,回家

郭芙蓉东西已经买齐了,回家

佟湘玉东西已经买齐了,回家

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-09 08:28:59

java并发编程之CyclicBarrier的相关文章

java并发编程之Master-Worker模式

Master-Worker模式适合在一个任务可以拆分成多个小任务来进行的情况下使用. package cn.fcl.masterworker; import java.util.HashMap; import java.util.Map; import java.util.Queue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; public c

Java并发编程之volatile的理解

Java并发编程之volatile关键字的理解 Java中每个线程都有自己的工作内存,类比于处理器的缓存,线程的工作内存中保存了被该线程使用到的变量的主内存的拷贝.线程读写变量都是直接在自己的工作内存中进行的,而何时刷新数据(指将修改的结果更新到主存或者把主存的变量读取覆盖掉工作内存中的值)是不确定的. volatile关键字是修饰字段的关键字,貌似是JDK1.5之后才有的,在多线程编程中,很大的几率会用到这个关键字,volatile修饰变量后该变量有这么一种效果:线程每一次读该变量都是直接从主

java并发编程之future模式

1.当你想并发去执行一段代码,但是还想获取这段代码的返回结果,那么future多线程模式就可以派上用场了,代码实现如下. public class Client { public Data request() { final FutureData futureData = new FutureData(); new Thread(new Runnable() { @Override public void run() { futureData.setRealData(new RealData()

Java并发编程之ConcurrentHashMap

ConcurrentHashMap ConcurrentHashMap是一个线程安全的Hash Table,它的主要功能是提供了一组和HashTable功能相同但是线程安全的方法.ConcurrentHashMap可以做到读取数据不加锁,并且其内部的结构可以让其在进行写操作的时候能够将锁的粒度保持地尽量地小,不用对整个ConcurrentHashMap加锁. ConcurrentHashMap的内部结构 ConcurrentHashMap为了提高本身的并发能力,在内部采用了一个叫做Segment

java并发编程之Guarded Suspention

当客户端请求速度远远大于服务端的处理速度,这时候就非常适合使用Guarded Suspention模式 package cn.fcl.guardendSuspension; import java.util.ArrayList; import java.util.List; public class RequestQueue { private List<Integer> integers = new ArrayList<Integer>(); public synchronize

Java并发编程之set集合的线程安全类你知道吗

Java并发编程之-set集合的线程安全类 Java中set集合怎么保证线程安全,这种方式你知道吗? 在Java中set集合是 本篇是<凯哥(凯哥Java:kagejava)并发编程学习>系列之<并发集合系列>教程的第二篇: 本文主要内容:Set集合子类底层分别是什么?基于底层为什么set的子类可以存放一个数据?怎么解决set线程安全问题? 一:Set集合子类 Set的三个子类分别是:HaseSet.TreeSet.LinkedHashSet.这三个都是线程不安全的.那么这三个子类

Java并发编程之Condition

1.使用synchronized中的等待和唤醒实现消费者和生产者模式 /** * 使用Synchronized实现消费者生产者模式 */ public class SynchronizedDemo { static List<Integer> list = new ArrayList<Integer>(); private static int maxNum = 5; // 消费者 private void Consumer(String name){ synchronized (

java并发编程之CountDownLatch与CyclicBarrier

CountDownLatch和CyclicBarrier是jdk concurrent包下非常有用的两个并发工具类,它们提供了一种控制并发流程的手段.本文将会提供一些应用场景,结合源码,对它们的具体实现以及如何使用做一个具体分析. CountDownLatch CountDownLatch允许一个或多个线程等待其他线程完成操作. CountDownLatch使用案例 需求:解析一个文件下多个txt文件数据,可以考虑使用多线程并行解析以提高解析效率.每一个线程解析一个文件里的数据,等到所有数据解析

java并发编程之CountDownLatch

一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待. 用给定的计数 初始化CountDownLatch.由于调用了 countDown() 方法,所以在当前计数到达零之前,await 方法会一直受阻塞.之后,会释放所有等待的线程,await 的所有后续调用都将立即返回.这种现象只出现一次--计数无法被重置.如果需要重置计数,请考虑使用 CyclicBarrier. CountDownLatch是一个通用同步工具,它有很多用途.将计数 1 初始化的CountDow