Java并发编程--CyclicBarrier

CyclicBarrier 是一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。CyclicBarrier支持一个可选的 Runnable
命令,在一组线程中的最后一个线程到达之后(但在释放所有线程之前),该命令只在每个屏障点运行一次。若在继续所有参与线程之前更新共享状态,此屏障操作 很有用。

业务需求

一个大型任务常常分配好多子任务去执行,只有当所有的子任务都执行完成时,才能执行主任务。比如在考试系统的抽题逻辑中,抽题是一个大型任务,包括抽出各种题型,比如:单选题、多选题、翻译题、听力题。抽完所有的题才能继续向下执行。按照咱们以前写代码的方式:先抽取单选题,再抽多选题,再抽翻译题,再抽听力题,假设每个抽题时间都为1s,那么完成一个抽题需要4s的时间,显然对电脑资源的利用率没有达到最优。那么我们如何提高性能呢?假设我们是4核的cpu,我们在抽单选题的时候可以同时抽多选题、翻译题和听力题,这样相当于是并行执行多个任务,那么抽完题需要的时间才是1s。

实现

有了上面的需求,那么下面我们来实现,如何抽题。

抽单选题类:

/**
 * 单选
 *
 * @author 康立贤
 *
 *         2015年5月19日2015
 */
public class SingleSelect implements Runnable {
	private Resutl result;
	private  CyclicBarrier barrier;
	private int number;
	public SingleSelect(Resutl result,CyclicBarrier barrier,int number) {
		this.result = result;
		this.barrier=barrier;
		this.number=number;
	}
	public SingleSelect(Resutl result,int number){
		this.result = result;
		this.number=number;
	}

	@Override
	public void run() {

		//System.out.println("单选==第"+number+"次==抽题===开始。。。");
		result.setSingleSelect("单选题。。。"+number);
		try {
			// 睡5s
		//	Thread.sleep((int) (Math.random() * 1000));
			System.out.println("单选==第"+number+"次==抽题===结束。。。");
			barrier.await();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (BrokenBarrierException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public void singleExam(){
		//System.out.println("单选==第"+number+"次==抽题===开始。。。");
		result.setSingleSelect("单选题。。。"+number);
		System.out.println("单选==第"+number+"次==抽题===结束。。。");

	}

}

抽多选、翻译、听力的类与上面的类似,在此省略。

存放抽题结果的类---Result.java

/**
 * 存放抽取到的试题
 * @author 康立贤
 *
 * 2015年5月19日2015
 */
public class Resutl {

	private String singleSelect;
	private String doubleSelect;
	private String translate;
	private String listening;
	public String getSingleSelect() {
		return singleSelect;
	}
	public void setSingleSelect(String singleSelect) {
		this.singleSelect = singleSelect;
	}
	public String getDoubleSelect() {
		return doubleSelect;
	}
	public void setDoubleSelect(String doubleSelect) {
		this.doubleSelect = doubleSelect;
	}
	public String getTranslate() {
		return translate;
	}
	public void setTranslate(String translate) {
		this.translate = translate;
	}
	public String getListening() {
		return listening;
	}
	public void setListening(String listening) {
		this.listening = listening;
	}

}

合并抽题结果类:---Combine.java

public class Combine implements Runnable{

	private Resutl result;
	public Combine(Resutl result){
		this.result=result;
	}
	@Override
	public synchronized  void  run() {
		//synchronized(this){
		System.out.println("所有抽题全部完毕");
		System.out.println(result.getDoubleSelect());
		System.out.println(result.getSingleSelect());
		System.out.println(result.getTranslate());
		System.out.println(result.getListening());
	}
}

客户端:

public class Exam3Pool {

	//目前性能比较好的方式
	public static void main(String[] args) {
		// 获取服务器的cpu个数
		int cpuNum = Runtime.getRuntime().availableProcessors();
		System.out.println("cpu的个数是:" + cpuNum);
		// 合适的线程数量是cpu数量
		ExecutorService pool = Executors.newFixedThreadPool(cpuNum);
		for(int i=0;i<200000;i++){
			Resutl result=new Resutl();
			Combine combine=new Combine(result);
			CyclicBarrier barrier=new CyclicBarrier(4,combine);
			DoubleSelect doubleSelect=new DoubleSelect(result,barrier,i);
			Linstening listening=new Linstening(result,barrier,i);
			SingleSelect singleSelect=new SingleSelect(result,barrier,i);
			Translate translate=new Translate(result,barrier,i);
			//多选抽题
			Thread thDouble=new Thread(doubleSelect);
			//听力抽题
			Thread thListen=new Thread(listening);
			//单选抽题
			Thread thSingle=new Thread(singleSelect);
			//翻译抽题
			Thread thTranslate=new Thread(translate);

			pool.execute(thDouble);
			pool.execute(thListen);
			pool.execute(thSingle);
			pool.execute(thTranslate);
		}

		pool.shutdown();
		System.out.println("主线程结束.........");
		//20s
		//21个线程

	}
}

总结:

通过设置公共屏障点的方式,我们可以使线程同步,同步完成后执行下面的功能,比如说执行完一个任务需要5个子任务,使用此种方式是只要有一个子任务没有完成,那么其余任务线程必须等待,不能再执行。我们考虑一下,如果一个子任务用的时间很长,那么整个任务执行完毕的时间取决于执行最长时间的子任务,其他子任务线程完全等待,这样资源并没有得到很好的利用,那么能不能在等待其他子任务完成之前让完成了任务的子线程去执行其他任务呢?这样可以使资源更充分的被利用?答案肯定是有的,下篇博客我们会解决这个问题,敬请期待~~~

时间: 2024-11-05 14:51:36

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

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

Java并发编程-总纲

Java 原生支持并发,基本的底层同步包括:synchronized,用来标示一个方法(普通,静态)或者一个块需要同步执行(某一时刻,只允许一个线程在执行代码块).volatile,用来标识一个变量是共享变量(线程不缓存),更新和读取是原子的.wait,线程等待某一个Object上的事件(notify事件,线程挂起,释放锁),需要在synchronized区中执行.notify,事件发生后,通知事件,通知一个挂起的线程,需要在synchronized区中执行.notifyAll,事件发生后,通知

《Java并发编程实战》第十六章 Java内存模型 读书笔记

Java内存模型是保障多线程安全的根基,这里仅仅是认识型的理解总结并未深入研究. 一.什么是内存模型,为什么需要它 Java内存模型(Java Memory Model)并发相关的安全发布,同步策略的规范.一致性等都来自于JMM. 1 平台的内存模型 在架构定义的内存模型中将告诉应用程序可以从内存系统中获得怎样的保证,此外还定义了一些特殊的指令(称为内存栅栏或栅栏),当需要共享数据时,这些指令就能实现额外的存储协调保证. JVM通过在适当的位置上插入内存栅栏来屏蔽在JVM与底层平台内存模型之间的