CyclicBarrier与CountDownLatch、栅栏与计数器

CyclicBarrier与CountDownLatch、栅栏与计数器
在多线程设计中,我猜常常会遇到线程间相互等待以及某个线程等待1个或多个线程的场景,比如多线程精密计算和大量数据处理,这里写下我自己的体会和理解。

   

    我想应该有很多办法,如果是简单的1:1关系,那么可以wait()和notify()解决,就像一把锁和一把钥匙;如果是1:N关系,这个1就需要关心N的所有状态了,最笨的办法是1可以去查看N当前的状态,轮询询问工作是否做完。而好点的办法是N做完后主动告诉1,然后N就会有2种选择,要么听从1的命令,要么继续干自己其他的活。

 

    用传统的方法我想应该是都能实现的,而JDK1.5提供了CyclicBarrier与CountDownLatch来解决了这两个问题,而她们的区别是:

    CyclicBarrier使所有线程相互等待,而CountDownLatch使一个或多个线程等待其他线程。区别类似上面蓝色字体,CountDownLatch不会等待其他线程了,只要做完自己的工作就干自己的活去了,也就是run()方法里其他的任务。

 

Example:

 

 

public   static   void  testCountDownLatch()  throws  InterruptedException {   
  CountDownLatch cdl
=new CountDownLatch(2);   
  ExecutorService exe
=Executors.newFixedThreadPool(2);   
   
class Bow implements  Runnable{   
    CountDownLatch cdl;   
    
public Bow(CountDownLatch cdl){   
    
this.cdl=cdl;    
    }
   
    
public void run(){   
     System.out.println(
"The bow is coming");   
     System.out.println(
"kick a bow ");   
     
this.cdl.countDown();   
     System.out.println(
"do other thing");   
     }
   
   }
   
  exe.execute(
new Bow(cdl));   
  exe.execute(
new Bow(cdl));   
  exe.shutdown();   
  System.out.println(
"Wait");   
    cdl.await();   
    System.out.println(
"End..");   
    
 }
   
  
    
public   static   void  main(String[] args)  {   
        
try {   
            Test.testCountDownLatch();   
        }
 catch (InterruptedException e) {   
        }
   
    }
  

 

输出的结果为:

 

The bow is coming
kick a bow
do other thing
Wait...
The bow is coming
kick a bow
do other thing
End..

 

如上所说do other thing不受影响。

 

写了一个CyclicBarrier的例子:

 

public   static   void  testCyclicBarrier()  throws  InterruptedException, BrokenBarrierException {
        CyclicBarrier barr
=new CyclicBarrier(2+1);
        
        ExecutorService exe
=Executors.newFixedThreadPool(2);
         
class Bow implements  Runnable{
             CyclicBarrier barr;
                
public Bow(CyclicBarrier barr){
                
this.barr=barr;    
                }

                
public void run(){
                    System.out.println(
"The bow is coming");
                    System.out.println(
"kick a down");
                    
try {
                        barr.await();
                    }
 catch (InterruptedException e) {
                        
// TODO Auto-generated catch block
                        e.printStackTrace();
                    }
 catch (BrokenBarrierException e) {
                        
// TODO Auto-generated catch block
                        e.printStackTrace();
                    }

                    System.out.println(
"do other thing");
                    }

            }

        exe.execute(
new Bow(barr));
        exe.execute(
new Bow(barr));
        exe.shutdown();
        System.out.println(
"Wait");
        barr.await();
       System.out.println(
"End..");
    
    }



    
public   static   void  main(String[] args)  {
        
try {
            Test.testCyclicBarrier();
        }
 catch (InterruptedException e) {
        }

        
catch (BrokenBarrierException e) {
        }

    }

 

输出结果为:

 

Wait...
The bow is coming
kick a down
The bow is coming
kick a down
do other thing
End..
do other thing

 

总结:

我们看到do other thing被阻塞了,直到最后才执行,可见,栅栏和计数器的目完全不同了。向Doug Lea牛人学习:)

 









在网上看到很多人对于CountDownLatch和CyclicBarrier的区别简单理解为CountDownLatch是一次性的,而CyclicBarrier在调用reset之后还可以继续使用。那如果只是这么简单的话,我觉得CyclicBarrier简单命名为ResetableCountDownLatch好了,显然不是的。
我的理解是,要从他们的设计目的去看这两个类。javadoc里面的描述是这样的。

CountDownLatch: A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.

CyclicBarrier : A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point.

可能是我的英语不够好吧, 我感觉从这个javadoc里面要准确理解他们的差异还是不容易的。
我的理解是

CountDownLatch : 一个线程(或者多个), 等待另外N个线程完成某个事情之后才能执行。   CyclicBarrier        : N个线程相互等待,任何一个线程完成之前,所有的线程都必须等待。
这样应该就清楚一点了,对于CountDownLatch来说,重点是那个“一个线程”, 是它在等待, 而另外那N的线程在把“某个事情”做完之后可以继续等待,可以终止。而对于CyclicBarrier来说,重点是那N个线程,他们之间任何一个没有完成,所有的线程都必须等待。



CountDownLatch 是计数器, 线程完成一个就记一个, 就像 报数一样, 只不过是递减的.
而CyclicBarrier更像一个水闸, 线程执行就想水流, 在水闸处都会堵住, 等到水满(线程到齐)了, 才开始泄流.

你可能感兴趣的:(CyclicBarrier与CountDownLatch、栅栏与计数器)