CountDownLatch
1)java.unit.concurrent.CountDownLatch用于同步一个或多个任务,
强制他们等待由其他任务执行的一组任务的完成;
使用一个初始计数值作为锁存器,通过调用countDownLatch,使锁存器递减;
当一个Latch锁存器递减至0之前,所有调用CountDownLatch.await 的任务线程都会一直被阻塞;
当该Latch锁存器 = 0 时,同时释放所有调用CountDownLatch.await 的任务线程对象;
2)CountDownLacth的2中典型用法:
①使一个线程在N个线程完成某项操作之前一直等待(或者在其某项工作完成N次之前一直等待);
CountDownLatch(1)可以作为一个开/关锁存器,在通过调用countDown的线程打开入口之前,所有调用await的线程都一直在入口等待;
//startSignal是一个启动信号,为driver在为执行所有worker做好准备之前,阻止所有worker执行;
//doneSiganl时一个完后信号,允许dirver在所有worker完成之前一直等待;
class Driver{
void main(){
CountDownLatch startSiganl = new CountDownLatch(1);
CountDownLatch doneSignal = new CountDownLacth(N);
ExecuteService exec = new Executors.newCachedThreadPool();
for(int i=0;i<N;i++)
exec.execute(new Worker(stratSignal,doneSingal));
<do some before all Worker tasks start running>
startSignal.countDown(); //let all threads start running
<do something while all Worker tasks are running>
doneSignal.await(); //wait for all to finish
<do something when all finished>
}
}
class Worker implements Runnable{
private final CountDownLatch stratSignal;
private final CountDownLatch doneSignal;
public Worker(CountDownLatch strat,CountDownLatch done){ startSiganl = start;doneSignal = done;}
public void run(){
try{
startSignal.await(); //let all worker wait;
<do Work>
doneSignal.countDown(); //count down latch;
}catch(InterrupedException ex){
}
}
②将一个问题分成N个部分,每个部分由描述该部分任务并让锁存器倒计时的Runnable来完成,然后将所有Runnable加入Executor队列
,当所有子部分完成后,协调线程就可以通过awiat;
(当线程需要使用这种方法反复计数时,可以改为使用
CyclicBarrier);
class Driver{
void main(){
CountDownLatch donwSignal = new CountDownLatch(N);
ExecutorService exec = Executors.newFixedThreadPool(N);
for(int i=0;i<N;i++)
exec.execute(new Worker(doneSiganl,i);
doneSiganl.await(); //wait for all to finish
}
}
class Worker implements Runnable{
private final CountDownLatch doneSiganl;
private final int i;
public Worker(CountDownLatch doneSignal,int i){this.doneSignal = doneSignal;this.i = i;}
public void run(){
try{
doWork(i);
doneSignal.countDown();
}catch(InterruptedException ex){
}
}
priavte void doWork(){
.......
}
}
CyclicBarrier
1)java.util.concurrent.CyclicBarrier 允许一组线程相互等待,直到到达某个公共屏障点(common barrier point),barrier在释放等待线程之后可以重用;
2)CyclicBarrier适用于并行分解设计,在涉及一组大小固定的线程的程序中,这些程序必须不时地相互等待(
即线程分布呈现为二维矩阵);
/*在这个例子中,每个worker单独处理矩阵的一行,在处理完所有的行之前,该线程会一直处于barrier处等待;
处理完所有的行后,由Runnable的mergeRows提供屏障操作,并合并这些行;
当合并者找到一个解决方案,done()返回true,所用Worker线程终止;
*/
class Solver{
final int N; //所有并行处理线程的数量
final float[][] data; //记录并行处理线程锁需要的数据,row:并行处理线程数量;col:每个线程在barrier执行块内需要的数据
final CyclicBarrier barrier; //记录并行线程共同的循环屏障对象
public Solver(float[][] matrix){
this.data = matrix;
N = matrix.length;
barrier = new CycilcBarrier(N,new Runnable(){
public void run(){ //每次启动barrier时执行的屏障操作,该操作由最后一个进入barrier的线程执行;
mergeRows();
}
});
ExectorService exec = Executors.newFixedThreadPool(N);
for(int i=0;i<N;i++)
exec.execute(new Worker(i));
<waitUnitlDone>
}
class Worker implements Runnable{
int row;
public Worker(int row){ this.row = row; }
public void run(){
while(!done()){ //判断合并者是否找到一个解决方案,当通过判断时,终止所有Worker线程
processRow(row); //每一个线程被分配的处理过程
try{
barrier.await();
}catch(InterruptedException ex){ //提前执行的线程中断
return;
}catch(BrokenBarrierException ex){ //但done()通过判定时,barrier被打破,每个线程的处理代码
return;
}
}
}
}
}