一个同步辅助类,它允许 一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier.
/*
问题:有三个工作者,有两个任务A,B,要求三个工作者反复工作=>完成A任务后,才可以开始B任务,都完成B任务后,一轮结束.
要求在三轮后结束工作.
*/
public class CyclicBarrierDemo1 {
public static void main(String[] args) {
CyclicBarrierDemo1 demo= new CyclicBarrierDemo1();
int n =3;
//线程池
ExecutorService e =Executors.newFixedThreadPool( n);
//监视器
Watch watch= demo. new Watch(3);
//定义n个线程等待的屏障
CyclicBarrier barrier= new CyclicBarrier(n ,watch );
for (int i =0;i new Worker(barrier ,watch ));
}
e.shutdown();
}
/*
* 工作者,当所有的工作者一次完成A,并且B后,监视器将会返回信号结束工作.
*/
class Worker implements Runnable{
private Watch watch ;
private CyclicBarrier barrier ;
public Worker(CyclicBarrier barrier ,Watch w ){
this .watch =w ;
this .barrier =barrier ;
}
public void taskA(){
System. out .println(Thread.currentThread().getName()+ "已完成任务A,等待" +barrier .getNumberWaiting());
}
public void taskB(){
System. out .println(Thread.currentThread().getName()+ "已完成任务B,等待" +barrier .getNumberWaiting());
}
public void end(){
System. out .println(Thread.currentThread().getName()+ "END" );
}
public void run(){
while (!watch .done()){
try {
Thread. sleep(( long) (Math.random()*10000));
taskA();
barrier.await();
Thread. sleep(( long) (Math.random()*10000));
taskB();
barrier.await();
} catch (InterruptedException e ){
e.printStackTrace();
} catch (BrokenBarrierException e ) {
e.printStackTrace();
}
}
end();
}
}
/*
* 构造函数接收一个参数,表示任务轮作的次数
*/
class Watch implements Runnable{
private boolean done = false;
private int num =0;
private int m =0;
public Watch(int num ){
this .num =num ;
}
public void run(){
if (++m %2==0){
System. out .println("第" +(m /2)+"轮任务结束" );
}
if (m /2==num )done = true;
}
public boolean done(){ return done;}
}
}
一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待
+示例程序1
/*
* 问题:模拟赛跑程式:有五个运动员,裁判员吹哨后,运动员开始冲向终点,所有运动员到达终点后,裁判员宣布比赛结束.
*/
public class CountDownLatchDemo1 {
public static void main(String[] args) throws InterruptedException {
CountDownLatchDemo1 demo= new CountDownLatchDemo1 ();
int n =5;
ExecutorService e =Executors.newFixedThreadPool( n);
CountDownLatch startCount =new CountDownLatch(1);
CountDownLatch doneCount =new CountDownLatch( n);
for (int i =0;i new Sporter(startCount ,doneCount ));
}
e.shutdown();
Thread. sleep(2000);
System. out .println("裁判员说:比赛开始" );
startCount .countDown();
doneCount .await();
System. out .println("裁判员说:比赛结束" );
}
class Sporter implements Runnable{
private CountDownLatch startCount ;
private CountDownLatch doneCount ;
public Sporter(CountDownLatch startCount ,CountDownLatch doneCount ){
this .startCount =startCount ;
this .doneCount =doneCount ;
}
public void run(){
while (true ){
try {
prepare();
startCount .await();
Thread. sleep(( long) (Math.random()*10000));
running();
doneCount .countDown();
break ;
} catch (InterruptedException e ) {
e.printStackTrace();
}
}
}
public void prepare(){
System. out .println(Thread.currentThread()+ "准备!" );
}
public void running(){
System. out .println(Thread.currentThread()+ "到达终点!" );
}
}
}
/*
* 问题:模拟电脑生产(启发程式)
* 生产一台电脑,可以按照组装的形式,先将各部分生产,在组装到一起.使用CountDoenLatch模拟生产过程.
* 现在假设电脑有5个组件,5个组件生产完成后,开始组装.
*/
public class CountDownLatchDemo2 {
public static void main(String[] args) throws InterruptedException {
CountDownLatchDemo2 demo= new CountDownLatchDemo2 ();
int n =5;
ExecutorService e =Executors.newFixedThreadPool( n);
CountDownLatch startCount =new CountDownLatch( n);
for (int i =1;i <=n ;i ++){
e.execute( demo. new Producer(startCount ,i ));
}
e.shutdown();
startCount .await();
System. out .println("开始组装!" );
}
class Producer implements Runnable{
private CountDownLatch startCount ;
private Object component ;
public Producer(CountDownLatch startCount ,Object component ){
this .startCount =startCount ;
this .component =component ;
}
public void run(){
while (true ){
try {
Thread. sleep(( long) (Math.random()*10000));
production();
startCount .countDown();
break ;
} catch (InterruptedException e ) {
e.printStackTrace();
}
}
}
private void production() {
System. out .println("组件" +component +"完成!" );
}
}
}
两者都使用了计数器,CyclicBarrier增加计数,当线程调用CyclicBarrier.await()时,计数器值增加,
如果计数器值小于规定数值,当前线程将一直处于等待.直到满足才继续.CountDownLatch减小计数,当线程调用CountDownLatch.await()时,当前线程将处于等待状态,直到计数器值为0,调用它的countDown()方法可以使计数器值减小1.
可以在对中对元素进行配对和交换的线程的同步点。每个线程将条目上的某个方法呈现给 exchange 方法,与伙伴线程进行匹配,并且在返回时接收其伙伴的对象。Exchanger 可能被视为 SynchronousQueue 的双向形式。Exchanger 可能在应用程序(比如遗传算法和管道设计)中很有用.
/*
* Exchange 使用示例:
* 问题: 交换两个线程的数据
*/
public class ExchangeDemo1 {
public static void main(String[] args) {
ExchangeDemo1 e= new ExchangeDemo1();
e.start();
}
Exchanger exchanger =new Exchanger<>();
ExecutorService service = Executors.newCachedThreadPool();
class Changer implements Runnable{
public void run(){
while (true ){
try {
Integer data= new Random().nextInt(900)+100;
Thread. sleep(1000);
//拿出数据,等待交换
Integer dx =exchanger .exchange( data);
System. out .println(data +"<=>" +dx );
} catch (InterruptedException e ) {
e.printStackTrace();
}
}
}
}
public void start(){
for (int i =0;i <3;i ++){
service.execute( new Changer());
}
service.shutdown();
}
}