论坛首页 Java企业应用论坛

CyclicBarrier与CountDownLatch、栅栏与计数器

浏览 8007 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2010-07-15   最后修改:2010-07-15
OO

    在多线程设计中,我猜常常会遇到线程间相互等待以及某个线程等待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牛人学习:)

 

 

 

 

 

 

   发表时间:2010-12-30   最后修改:2010-12-30
C_J 写道

    在多线程设计中,我猜常常会遇到线程间相互等待以及某个线程等待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牛人学习:)

 

 

 

 

 

 


我复制了你的第二部分程序代码(CyclicBarrier部分),经过测试执行,每次结果都不一样。其中也会出现你列在下面的输出。

-------------------------------------------------------------

The bow is coming

kick a down

Wait...

The bow is coming

kick a down

do other thing

do other thing

End..

-------------------------------------------------------------

Wait...

The bow is coming

kick a down

The bow is coming

kick a down

End..

do other thing

do other thing

-------------------------------------------------------------

Wait...

The bow is coming

kick a down

The bow is coming

kick a down

do other thing

End..

do other thing

-------------------------------------------------------------

0 请登录后投票
   发表时间:2010-12-31  
=。= 结果是正确的。你理解的有偏差....

CyclicBarrier就是保证“do other thing” 在 “The bow is coming”之后。
0 请登录后投票
   发表时间:2011-03-24  
引用
CountDownLatch不会等待其他线程了,只要做完自己的工作就干自己的活去了,也就是run()方法里其他的任务。

这应该是CyclicBarrier吧?
兄弟你的例子来说明问题似乎让人不好琢磨。我也写了两个例子,大家一起学习下

public class CyclicBarrierTest {

	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();
	}
	
}



public class CountdownLatchTest {

	public static void main(String[] args) {
		ExecutorService service = Executors.newCachedThreadPool();
		final CountDownLatch cdOrder = new CountDownLatch(1);
		final CountDownLatch cdAnswer = new CountDownLatch(3);		
		for(int i=0;i<3;i++){
			Runnable runnable = new Runnable(){
					public void run(){
					try {
						System.out.println("线程" + Thread.currentThread().getName() + 
								"正准备接受命令");						
						cdOrder.await();
						System.out.println("线程" + Thread.currentThread().getName() + 
						"已接受命令");								
						Thread.sleep((long)(Math.random()*10000));	
						System.out.println("线程" + Thread.currentThread().getName() + 
								"回应命令处理结果");						
						cdAnswer.countDown();						
					} catch (Exception e) {
						e.printStackTrace();
					}				
				}
			};
			service.execute(runnable);
		}		
		try {
			Thread.sleep((long)(Math.random()*10000));
		
			System.out.println("线程" + Thread.currentThread().getName() + 
					"即将发布命令");						
			cdOrder.countDown();
			System.out.println("线程" + Thread.currentThread().getName() + 
			"已发送命令,正在等待结果");	
			cdAnswer.await();
			System.out.println("线程" + Thread.currentThread().getName() + 
			"已收到所有响应结果");	
		} catch (Exception e) {
			e.printStackTrace();
		}				
		service.shutdown();

	}
}
0 请登录后投票
   发表时间:2011-04-05  
不是的,CyclicBarrier阻塞,CountDownLatch不阻塞。

你的第一个例子:
ExecutorService service = Executors.newCachedThreadPool();  
有一点危险,需要注意下Pool的大小,不然程序有可能永远阻塞。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics