java.util.concurrent包(6)——CyclicBarrier使用

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

CyclicBarrier类似于CountDownLatch也是个计数器, 不同的是CyclicBarrier数的是调用了CyclicBarrier.await()进入等待的线程数, 当线程数达到了CyclicBarrier初始时规
定的数目时,所有进入等待状态的线程被唤醒并继续。CyclicBarrier就象它名字的意思一样可看成是个障碍, 所有的线程必须到齐后才能一起通过这个障碍。 CyclicBarrier初 始时还可带一个Runnable的参数,此Runnable任务在CyclicBarrier的数目达到后,所有其它线程被唤醒前被执行。


构造方法摘要
CyclicBarrier(int parties) 
创建一个新的CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,但它不会在每个barrier上执行预定义的操作。

CyclicBarrier(int parties, Runnable barrierAction) 
创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,并在启动 barrier 时执行给定的屏障操作,该操作由最后一个进入barrier的线程执行
 

方法摘要
int await() 
在所有参与者都已经在此barrier上调用await方法之前,将一直等待

int await(long timeout, TimeUnit unit) 
在所有参与者都已经在此屏障上调用 await 方法之前,将一直等待

int getNumberWaiting() 
返回当前在屏障处等待的参与者数目

int getParties() 
返回要求启动此 barrier 的参与者数目

boolean isBroken() 
查询此屏障是否处于损坏状态

void reset() 
将屏障重置为其初始状态

例一
public class RunnerTask implements Runnable
{
private final CyclicBarrier cyclicBarrier;
private String name;

public RunnerTask(CyclicBarrier cyclicBarrier, String name)
{
super();
this.name = name;
this.cyclicBarrier = cyclicBarrier;
}

public void run()
{
try
{
try
{
// 模拟等待
Thread.sleep(new Random().nextInt(5) * 1000);
System.out.println(name + "准备......");
cyclicBarrier.await();
System.out.println(name + "跑!");
}
catch (BrokenBarrierException e)
{
e.printStackTrace();
}
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}

public class RunnerTest
{
public static void main(String[] args)
{
CyclicBarrier cyclicBarrier = new CyclicBarrier(5);
for (int i = 1; i <= 5; i++)
{
new Thread(new RunnerTask(cyclicBarrier, "运动员" + i)).start();
}
}
}
运动员3准备......
运动员2准备......
运动员4准备......
运动员5准备......
运动员1准备......
运动员3跑!
运动员2跑!
运动员1跑!
运动员5跑!
运动员4跑!


例二
public class CyclicBarrierTest2
{
public static void main(String[] args)
{
ExecutorService service = Executors.newCachedThreadPool();
final CyclicBarrier cb = new CyclicBarrier(3);
for (int i = 0; i < 3; i++)
{
Runnable runnable = new Runnable()
{
public void run()
{
try
{
Thread.sleep((long) (Math.random() * 10000));
System.out.println("线程" + Thread.currentThread().getName() 
+ "即将到达集合地点1,当前已有" + cb.getNumberWaiting() + "个已经到达,正在等候");
cb.await();


Thread.sleep((long) (Math.random() * 10000));
System.out.println("线程" + Thread.currentThread().getName() 
+ "即将到达集合地点2,当前已有" + cb.getNumberWaiting() + "个已经到达,正在等候");
cb.await();
Thread.sleep((long) (Math.random() * 10000));
System.out.println("线程" + Thread.currentThread().getName() 
+ "即将到达集合地点3,当前已有" + cb.getNumberWaiting() + "个已经到达,正在等候");
cb.await();

}
catch (Exception e)
{
e.printStackTrace();
}
}
};
service.execute(runnable);
}
service.shutdown();
}
}
线程pool-1-thread-1即将到达集合地点1,当前已有0个已经到达,正在等候
线程pool-1-thread-3即将到达集合地点1,当前已有1个已经到达,正在等候
线程pool-1-thread-2即将到达集合地点1,当前已有2个已经到达,正在等候
线程pool-1-thread-3即将到达集合地点2,当前已有0个已经到达,正在等候
线程pool-1-thread-2即将到达集合地点2,当前已有1个已经到达,正在等候
线程pool-1-thread-1即将到达集合地点2,当前已有2个已经到达,正在等候
线程pool-1-thread-1即将到达集合地点3,当前已有0个已经到达,正在等候
线程pool-1-thread-3即将到达集合地点3,当前已有1个已经到达,正在等候
线程pool-1-thread-2即将到达集合地点3,当前已有2个已经到达,正在等候


例三
public class CyclicBarrierTest
{
public static void main(String[] args)
{
ExecutorService service = Executors.newCachedThreadPool();
final CyclicBarrier cb = new CyclicBarrier(3, new Runnable()
{
public void run()
{
System.out.println("********我最先执行***********");
}
});
for (int i = 0; i < 3; i++)
{
Runnable runnable = new Runnable()
{
public void run()
{
try
{
Thread.sleep((long) (Math.random() * 10000));
System.out.println("线程" + Thread.currentThread().getName() 
+ "即将到达集合地点1,当前已有" + cb.getNumberWaiting() + "个已经到达,正在等候");
cb.await();


Thread.sleep((long) (Math.random() * 10000));
System.out.println("线程" + Thread.currentThread().getName() 
+ "即将到达集合地点2,当前已有" + cb.getNumberWaiting() + "个已经到达,正在等候");
cb.await();

Thread.sleep((long) (Math.random() * 10000));
System.out.println("线程" + Thread.currentThread().getName() 
+ "即将到达集合地点3,当前已有" + cb.getNumberWaiting() + "个已经到达,正在等候");
cb.await();
}
catch (Exception e)
{
e.printStackTrace();
}
}
};
service.execute(runnable);
}
service.shutdown();
}
}
线程pool-1-thread-1即将到达集合地点1,当前已有0个已经到达,正在等候
线程pool-1-thread-3即将到达集合地点1,当前已有1个已经到达,正在等候
线程pool-1-thread-2即将到达集合地点1,当前已有2个已经到达,正在等候
********我最先执行***********
线程pool-1-thread-1即将到达集合地点2,当前已有0个已经到达,正在等候
线程pool-1-thread-3即将到达集合地点2,当前已有1个已经到达,正在等候
线程pool-1-thread-2即将到达集合地点2,当前已有2个已经到达,正在等候
********我最先执行***********
线程pool-1-thread-1即将到达集合地点3,当前已有0个已经到达,正在等候
线程pool-1-thread-3即将到达集合地点3,当前已有1个已经到达,正在等候
线程pool-1-thread-2即将到达集合地点3,当前已有2个已经到达,正在等候
********我最先执行***********

原帖地址:http://www.cnblogs.com/liuling/p/2013-8-21-01.html
目录
相关文章
|
3月前
|
安全 Java API
JAVA并发编程JUC包之CAS原理
在JDK 1.5之后,Java API引入了`java.util.concurrent`包(简称JUC包),提供了多种并发工具类,如原子类`AtomicXX`、线程池`Executors`、信号量`Semaphore`、阻塞队列等。这些工具类简化了并发编程的复杂度。原子类`Atomic`尤其重要,它提供了线程安全的变量更新方法,支持整型、长整型、布尔型、数组及对象属性的原子修改。结合`volatile`关键字,可以实现多线程环境下共享变量的安全修改。
|
1月前
|
Java Android开发
Eclipse 创建 Java 包
Eclipse 创建 Java 包
33 1
|
2月前
|
Java Apache Maven
Java/Spring项目的包开头为什么是com?
本文介绍了 Maven 项目的初始结构,并详细解释了 Java 包命名惯例中的域名反转规则。通过域名反转(如 `com.example`),可以确保包名的唯一性,避免命名冲突,提高代码的可读性和逻辑分层。文章还讨论了域名反转的好处,包括避免命名冲突、全球唯一性、提高代码可读性和逻辑分层。最后,作者提出了一个关于包名的问题,引发读者思考。
101 0
Java/Spring项目的包开头为什么是com?
|
3月前
|
Java API 数据处理
Java 包(package)的作用详解
在 Java 中,包(package)用于组织和管理类与接口,具有多项关键作用:1)系统化组织代码,便于理解和维护;2)提供命名空间,避免类名冲突;3)支持访问控制,如 public、protected、默认和 private,增强封装性;4)提升代码可维护性,实现模块化开发;5)简化导入机制,使代码更简洁;6)促进模块化编程,提高代码重用率;7)管理第三方库,避免命名冲突;8)支持 API 设计,便于功能调用;9)配合自动化构建工具,优化项目管理;10)促进团队协作,明确模块归属。合理运用包能显著提升代码质量和开发效率。
239 4
|
3月前
|
Java
JAVA并发编程系列(9)CyclicBarrier循环屏障原理分析
本文介绍了拼多多面试中的模拟拼团问题,通过使用 `CyclicBarrier` 实现了多人拼团成功后提交订单并支付的功能。与之前的 `CountDownLatch` 方法不同,`CyclicBarrier` 能够确保所有线程到达屏障点后继续执行,并且屏障可重复使用。文章详细解析了 `CyclicBarrier` 的核心原理及使用方法,并通过代码示例展示了其工作流程。最后,文章还提供了 `CyclicBarrier` 的源码分析,帮助读者深入理解其实现机制。
|
3月前
|
Java 数据安全/隐私保护
Java 包(package)的使用详解
Java中的包(`package`)用于组织类和接口,避免类名冲突并控制访问权限,提升代码的可维护性和可重用性。通过`package`关键字定义包,创建相应目录结构即可实现。包可通过`import`语句导入,支持导入具体类或整个包。Java提供多种访问权限修饰符(`public`、`protected`、`default`、`private`),以及丰富的标准库包(如`java.lang`、`java.util`等)。合理的包命名和使用对大型项目的开发至关重要。
199 2
|
4月前
|
JavaScript Java API
Java日志通关(二) - Slf4j+Logback 整合及排包
作者日常在与其他同学合作时,经常发现不合理的日志配置以及五花八门的日志记录方式,后续作者打算在团队内做一次Java日志的分享,本文是整理出的系列文章第二篇。
|
4月前
|
Java Maven 数据库
|
4月前
|
Java
Java应用结构规范问题之在biz层的convert包实现转换的问题如何解决
Java应用结构规范问题之在biz层的convert包实现转换的问题如何解决
|
4月前
|
Java
Java 中 CyclicBarrier 和 CountDownLatch 的区别
【8月更文挑战第22天】
134 4