`
C_J
  • 浏览: 128131 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

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牛人学习:)

 

 

 

 

 

 

分享到:
评论
4 楼 C_J 2011-04-05  
不是的,CyclicBarrier阻塞,CountDownLatch不阻塞。

你的第一个例子:
ExecutorService service = Executors.newCachedThreadPool();  
有一点危险,需要注意下Pool的大小,不然程序有可能永远阻塞。
3 楼 zhaolei415 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();

	}
}
2 楼 C_J 2010-12-31  
=。= 结果是正确的。你理解的有偏差....

CyclicBarrier就是保证“do other thing” 在 “The bow is coming”之后。
1 楼 aunox 2010-12-30  
<div class="quote_title">C_J 写道</div>
<div class="quote_div">
<p>    在多线程设计中,我猜常常会遇到线程间相互等待以及某个线程等待1个或多个线程的场景,比如多线程精密计算和大量数据处理,这里写下我自己的体会和理解。</p>
<p>    </p>
<p>    我想应该有很多办法,如果是简单的1:1关系,那么可以wait()和notify()解决,就像一把锁和一把钥匙;如果是1:N关系,这个1就需要关心N的所有状态了,最笨的办法是1可以去查看N当前的状态,轮询询问工作是否做完。而好点的办法是N做完后主动告诉1,<span style="color: #0000ff;">然后N就会有2种选择,要么听从1的命令,要么继续干自己其他的活。</span></p>
<p> </p>
<p>    用传统的方法我想应该是都能实现的,而JDK1.5提供了CyclicBarrier与CountDownLatch来解决了这两个问题,而她们的区别是:</p>
<p>    CyclicBarrier使所有线程相互等待,而CountDownLatch使一个或多个线程等待其他线程。区别类似上面蓝色字体,CountDownLatch不会等待其他线程了,只要做完自己的工作就干自己的活去了,也就是run()方法里其他的任务。</p>
<p> </p>
<p>Example:</p>
<pre name="code" class="java">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) {
}
}</pre>
<p> </p>
<p>输出的结果为:</p>
<p> </p>
<p>The bow is coming<br>kick a bow <br><span style="color: #0000ff;">do other thing</span><br>Wait...<br>The bow is coming<br>kick a bow <br><span style="color: #0000ff;">do other thing</span><br>End..</p>
<p> </p>
<p>如上所说do other thing不受影响。</p>
<p> </p>
<p>写了一个CyclicBarrier的例子:</p>
<pre name="code" class="java">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) {
}
}</pre>
<p> </p>
<p>输出结果为:</p>
<p> </p>
<p>Wait...<br>The bow is coming<br>kick a down<br>The bow is coming<br>kick a down<br><span style="color: #0000ff;">do other thing</span><br>End..<br><span style="color: #0000ff;">do other thing</span></p>
<p> </p>
<p><strong><span style="color: #ff6600;">总结:</span></strong></p>
<p>我们看到do other thing被阻塞了,直到最后才执行,可见,栅栏和计数器的目完全不同了。向Doug Lea牛人学习:)</p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
</div>
<p><br>我复制了你的第二部分程序代码(CyclicBarrier部分),经过测试执行,每次结果都不一样。其中也会出现你列在下面的输出。 </p>
<p>-------------------------------------------------------------</p>
<p>The bow is coming </p>
<p>kick a down </p>
<p>Wait... </p>
<p>The bow is coming </p>
<p>kick a down </p>
<p>do other thing </p>
<p>do other thing </p>
<p>End.. </p>
<p>------------------------------------------------------------- </p>
<p>Wait... </p>
<p>The bow is coming </p>
<p>kick a down </p>
<p>The bow is coming </p>
<p>kick a down </p>
<p>End.. </p>
<p>do other thing </p>
<p>do other thing </p>
<p>------------------------------------------------------------- </p>
<p>Wait... </p>
<p>The bow is coming </p>
<p>kick a down </p>
<p>The bow is coming </p>
<p>kick a down </p>
<p>do other thing </p>
<p>End.. </p>
<p>do other thing </p>
<p>-------------------------------------------------------------</p>

相关推荐

    Java并发编程之栅栏(CyclicBarrier)实例介绍

    - **计数机制**:CountDownLatch的计数器只能递减且不可重置,而CyclicBarrier的计数器可以在所有线程到达屏障点后重置。 - **等待策略**:CountDownLatch的线程等待是单向的,而CyclicBarrier可以让所有线程一起...

    详解java多线程的同步控制

    目录线程安全 Thread Safety重入锁 ReentrantLock读写锁 ReadWriteLock倒计数器 CountDownLatch循环栅栏 CyclicBarrier信号量 Semaphore 线程安全 Thread Safety JMM JMM(Java Memory Model)是一种基于计算机内存...

    Java并发编程之闭锁与栅栏的实现

    闭锁,由`java.util.concurrent.CountDownLatch`类实现,它是一个计数器,初始化时传入一个整数count,表示需要等待的线程数量。每当一个线程完成其任务时,会调用`countDown()`方法,将计数器减一。所有线程完成...

    狂神JUC并发笔记大全+Linux等资料

    JUC(Java Util Concurrency)是Java提供的并发工具包,包含了许多高级并发组件,如Semaphore(信号量)、CyclicBarrier(回环栅栏)、CountDownLatch(计数器门锁)等,它们极大地简化了并发编程的复杂性。...

    并发编程

    Java平台提供了丰富的并发工具,如ExecutorService、Semaphore(信号量)、CountDownLatch(计数器)、CyclicBarrier(回环栅栏)等,这些工具帮助开发者有效地管理和控制并发任务。例如,ExecutorService允许创建...

    java并发编程:设计原则与模式.rar

    Java并发工具类库(java.util.concurrent)是并发编程中的另一个重要主题,包括Atomic类(提供原子操作)、Semaphore(信号量)、CountDownLatch(计数器门锁)、CyclicBarrier(循环栅栏)和Exchanger(交换器)等...

    java同步

    - **java.util.concurrent**包提供了一系列并发工具类,如Semaphore(信号量)、CountDownLatch(计数器)、CyclicBarrier(回环栅栏)和Phaser(屏障)等,它们可以帮助实现复杂的同步策略。 - **Semaphore**:...

    JAVA并发编程实践(中文)含源码

    最后,Java并发工具类,如Semaphore(信号量)、CyclicBarrier(回环栅栏)、CountDownLatch(计数器门闩)和Exchanger(交换器),提供了更高级的同步和协调机制,有助于解决复杂并发场景的问题。 通过阅读《JAVA...

    Java多线程与线程安全实践-基于Http协议的断点续传.zip

    5. **并发工具类**:Java并发包(java.util.concurrent)包含丰富的工具类,如Semaphore(信号量)、CyclicBarrier(回环栅栏)、CountDownLatch(计数器门锁)等,帮助开发者高效地处理并发问题。 **基于Http协议...

    商汤科技Java面试题

    - **并发工具类**:Semaphore(信号量)、CyclicBarrier(回环栅栏)、CountDownLatch(计数器)的应用。 4. **IO/NIO**: - **传统IO**:流的概念,字节流与字符流,缓冲流的使用。 - **NIO**:非阻塞I/O,...

    Java并发编程实践多线程

    第二章至第四章可能会深入讨论Java并发工具,如Executor框架、Semaphore信号量、CountDownLatch计数器、CyclicBarrier回环栅栏、Future和Callable接口等。这些工具能够帮助开发者有效地控制线程执行、协调任务和管理...

    聚焦高并发、分布式集群、微服务架构迭代的互联网电商项目(Java技术栈).zip

    此外,Java并发工具类如Semaphore(信号量)、CountDownLatch(计数器)和CyclicBarrier(循环栅栏)等可帮助开发者有效地管理并发资源。 2. 分布式集群: 分布式集群是将单一应用分散到多个节点上,以提升系统的...

    java线程入门(内附详细的开发环境讲解)

    此外,Java还提供了Semaphore(信号量)、CyclicBarrier(回环栅栏)、CountDownLatch(计数器门锁)和Phaser(阶段器)等高级同步工具,以应对更复杂的并发场景。 线程的状态包括新建、就绪、运行、阻塞和终止,...

    java并发编程艺术源码

    3. **并发工具类**:Java并发包(java.util.concurrent)提供了丰富的并发工具类,如Semaphore(信号量)、CyclicBarrier(循环栅栏)、CountDownLatch(计数器门锁)、Future和Callable接口等,它们在解决特定并发...

    Java面试JVM+多线程重点突破.zip

    8. **并发工具类**:如Semaphore(信号量)、CountDownLatch(计数器)、CyclicBarrier(回环栅栏)和 Phaser(阶段器)等,它们在多线程编程中提供了灵活的同步和协调机制。 9. **并发集合**:如ConcurrentHashMap...

    Java 并发编程实战 中英文+代码示例

    3. **并发工具类**:如Semaphore(信号量)、CountDownLatch(计数器)、CyclicBarrier(回环栅栏)和Exchanger(交换器)等,这些都是Java并发库提供的重要工具,用于实现复杂的同步和协作机制。 4. **并发集合**...

    Java并发编程设计原则和模式

    2. CyclicBarrier:循环栅栏,允许一组线程等待彼此到达某个点后再一起继续执行。 3. Semaphore:信号量,用于控制对有限资源的访问权限,常用于限流和同步。 六、线程安全与内存模型 1. Java内存模型(JMM):定义...

    2019互联网面试题第2季.mmap.zip

    4. **并发工具类**:学习Semaphore(信号量)、CyclicBarrier(回环栅栏)、CountDownLatch(倒计时器)和Exchanger(交换器)等工具类,以及如何在实际项目中应用。 5. **线程池**:理解ExecutorService、...

    一些学习资料(EJB,word,excel,java多线程)

    6. **并发工具类**:介绍Java并发库(java.util.concurrent)中的各种工具类,如Semaphore(信号量)、CountDownLatch(计数器)、CyclicBarrier(回环栅栏)等,用于更高级的线程协调。 7. **实战案例**:可能包含...

    多线程文档.zip

    2. **并发锁**:在高并发环境中,Java提供了更为高效的并发锁,如Semaphore(信号量)、CountDownLatch(计数器)和CyclicBarrier(回环栅栏)。这些工具允许精确控制线程的同步和通信,有助于优化多线程程序的性能...

Global site tag (gtag.js) - Google Analytics