新书Java并发编程系统与模型已上线,欢迎拜读。
前言
barrier(屏障)与互斥量,读写锁,自旋锁不同,它不是用来保护临界区的。相反,它跟条件变量一样,是用来协同多线程一起工作的。
条件变量是多线程间传递状态的改变来达到协同工作的效果。屏障是多线程各自做自己的工作,如果某一线程完成了工作,就等待在屏障那里,直到其他线程的工作都完成了,再一起做别的事。举个通俗的例子:
1.对于条件变量。在接力赛跑里,1号队员开始跑的时候,2,3,4号队员都站着不动,直到1号队员跑完一圈,把接力棒给2号队员,2号队员收到接力棒后就可以跑了,跑完再给3号队员。这里这个接力棒就相当于条件变量,条件满足后就可以由下一个队员(线程)跑。
2.对于屏障:在百米赛跑里,比赛没开始之前,每个运动员都在赛场上自由活动,有的热身,有的喝水,有的跟教练谈论。比赛快开始时,准备完毕的运动员就预备在起跑线上,如果有个运动员还没准备完(除去特殊情况),他们就一直等,直到运动员都在起跑线上,裁判喊口号后再开始跑。这里的起跑线就是屏障,做完准备工作的运动员都等在起跑线,直到其他运动员也把准备工作做完。
java.util.concurrent.CyclicBarrier类是一个同步机制。它可以通过一些算法来同步线程处理的过程。换言之,就是所有的线程必须等待对方,直到所有的线程到达屏障,然后继续运行。下面这个图可以说明:
两个线程等待循环屏障
两个线程通过调用CyclicBarrier的 await() 相互等待对方,一旦所有的线程都在CyclicBarrier中等待,然后所有的线程一起释放然后继续执行。
创建循环屏障
当你要创建CyclicBarrier的时候必须指定在释放他们前有多少个线程等待,下面是一个例子:
CyclicBarrier barrier = new CyclicBarrier(2);复制代码
在CyclicBarrier等待
下面是在CyclicBarrier处等待:
barrier.await();复制代码
你也可以指线程等待的超时时间,当等待超时的时候,线程依然会被释放。即使并不是所有的线程都开始在CyclicBarrier等待。下面这行代码指定超时时间:
barrier.await(10, TimeUnit.SECONDS);复制代码
所有线程在CyclicBarrier等待,是指:
• 最后一个线程到达(调用await方法)
• 一个线程被被另外一个线程中断(另外一个线程调用了这个现场的interrupt()方法)
• 其中一个等待的线程被中断
• 其中一个等待的线程超时
• 一个外部的线程调用了yclicBarrier.reset()方法。
CyclicBarrier Action
CyclicBarrier 支持一个Runnable屏障动作。当最后一个线程到达的时候,这个Runable对象就可以被执行。你需要将这个Runable屏障动作放置在他的构造器中,就像这样:
Runnable barrierAction = ... ;
CyclicBarrier barrier = new CyclicBarrier(2, barrierAction);复制代码
下面这个例子说明了如何使用CyclicBarrier:
Runnable barrier1Action = new Runnable() {
public void run() {
System.out.println("BarrierAction 1 executed ");
}
};
Runnable barrier2Action = new Runnable() {
public void run() {
System.out.println("BarrierAction 2 executed ");
}
};
CyclicBarrier barrier1 = new CyclicBarrier(2, barrier1Action);
CyclicBarrier barrier2 = new CyclicBarrier(2, barrier2Action);
CyclicBarrierRunnable barrierRunnable1 =
new CyclicBarrierRunnable(barrier1, barrier2);
CyclicBarrierRunnable barrierRunnable2 =
new CyclicBarrierRunnable(barrier1, barrier2);
new Thread(barrierRunnable1).start();
new Thread(barrierRunnable2).start();
Here is the CyclicBarrierRunnable class:复制代码
下面是CyclicBarrierRunnable类:
public class CyclicBarrierRunnable implements Runnable{
CyclicBarrier barrier1 = null;
CyclicBarrier barrier2 = null;
public CyclicBarrierRunnable(
CyclicBarrier barrier1,
CyclicBarrier barrier2) {
this.barrier1 = barrier1;
this.barrier2 = barrier2;
}
public void run() {
try {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() +
" waiting at barrier 1");
this.barrier1.await();
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() +
" waiting at barrier 2");
this.barrier2.await();
System.out.println(Thread.currentThread().getName() +
" done!");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}复制代码
下面是控制台的输出。但是要注意有时候输出的顺序会发生变化,有时候是Thread-0先打印,有时候是Thread-1先打印。
Thread-0 waiting at barrier 1
Thread-1 waiting at barrier 1
BarrierAction 1 executed
Thread-1 waiting at barrier 2
Thread-0 waiting at barrier 2
BarrierAction 2 executed
Thread-0 done!
Thread-1 done!复制代码