当前位置:首页 > 开发 > 编程语言 > Java > 正文

java 同步之CountDownLatch、CyclicBarrier

发表于: 2014-10-09   作者:墙头上一根草   来源:转载   浏览:
摘要:     java api提供了很多线程同步有关的类和接口,所有的源码都在java.util.concurrent这个包中,主要原子的类和线程安全的集合框架,还有就是重要的锁的实现,锁的实现在juc的locks这个包中,本节不讨论锁的实现,主要是说明和使用juc下的CountDownLatch和CyclicBarrier     CountDow

    java api提供了很多线程同步有关的类和接口,所有的源码都在java.util.concurrent这个包中,主要原子的类和线程安全的集合框架,还有就是重要的锁的实现,锁的实现在juc的locks这个包中,本节不讨论锁的实现,主要是说明和使用juc下的CountDownLatch和CyclicBarrier

 

  CountDownLatch  源码解释<!-- Generated by javadoc (build 1.6.0-beta2) on Fri Mar 09 12:52:55 CST 2007 -->

<noscript></noscript>

             一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。

用给定的计数 初始化 CountDownLatch。由于调用了 countDown() 方法,所以在当前计数到达零之前,await 方法会一直受阻塞。之后,会释放所有等待的线程,await 的所有后续调用都将立即返回。这种现象只出现一次——计数无法被重置。如果需要重置计数,请考虑使用 CyclicBarrier

CountDownLatch 是一个通用同步工具,它有很多用途。将计数 1 初始化的 CountDownLatch 用作一个简单的开/关锁存器,或入口:在通过调用 countDown() 的线程打开入口前,所有调用 await 的线程都一直在入口处等待。用 N 初始化的 CountDownLatch 可以使一个线程在 N 个线程完成某项操作之前一直等待,或者使其在某项操作完成 N 次之前一直等待。

CountDownLatch 的一个有用特性是,它不要求调用 countDown 方法的线程等到计数到达零时才继续,而在所有线程都能通过之前,它只是阻止任何线程继续通过一个 await

           <!-- Generated by javadoc (build 1.6.0-beta2) on Fri Mar 09 12:52:55 CST 2007 -->

    CyclicBarrier  源码解释

<noscript></noscript>

              一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。

CyclicBarrier 支持一个可选的 Runnable 命令,在一组线程中的最后一个线程到达之后(但在释放所有线程之前),该命令只在每个屏障点运行一次。若在继续所有参与线程之前更新共享状态

 

     从api对这两个类的说明可以看出,这两个类都是同步辅助类,这两个类有些相似之处都提供屏障点,即线程在到达屏障点之前都会等待, CountDownLatch的作用是允许1或N个线程等待其他线程完成执行;而CyclicBarrier则是允许N个线程相互等待。
CountDownLatch的计数器无法被重置;CyclicBarrier的计数器可以被重置后使用,因此它被称为是循环的barrie

 

    以下是这两个类的使用例子,即把一个大的work分成若干的小work去执行,然后最后计算总的,本例是计算5亿次的加1操作,分别用CountDownLatch 和 CyclicBarrier 实现,直接贴代码部分

 

     

      /**     
* Test2.java Create on 2014年10月9日    
*     
* Copyright (c) 2014年10月9日 by dzh
*     
* @author <a href="xingyu@gw.com.cn">xingyu</a>    
* @version 0.0.1
*    
*/
package org.dzh.lock;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;

/**@className:Test2.java

 * @description:分段计算5亿次的+1

 * @date 2014年10月9日 上午10:29:29
 */
public class Test2 {
    private static List<Integer> result = new ArrayList<>();
    
    /**@className:Test2.java
    
     * @description:CountDownLatch 实现计算
    
     * @date 2014年10月9日 上午10:30:08
     */
    public static class CDL implements Runnable{
        private final CountDownLatch startSignal;
        private final CountDownLatch doneSignal;
        
        
        CDL(CountDownLatch startSignal,CountDownLatch doneSignal){
            this.startSignal = startSignal;
            this.doneSignal = doneSignal;
        }
        
        @Override
        public void run() {
            try {
                
                this.startSignal.await();
                doWork();
                this.doneSignal.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        
        void doWork(){
            System.out.println("当前线程的名字是: "+Thread.currentThread().getName());
        }
    }
    
    public static void mainCDL() throws InterruptedException{
        CountDownLatch startSignal = new CountDownLatch(1);//所有的线程都准备好了再开始工作
        CountDownLatch doneSignal = new CountDownLatch(5);//所有的线程都运算结束在开始工作
        
        for (int i = 0; i < 5; i++) {
            new Thread(new CDL(startSignal, doneSignal),"线程"+i).start();
        }
        dosomethingElse();
        startSignal.countDown();//startSignal计数减一,意味着startSignal.await被激活开始工作
        System.out.println("当前数量为:"+startSignal.getCount());
        dosomethingElse();
        doneSignal.await();//在doneSignal计数变为0之前一直等待
        System.out.println("是否结束!");
    }
    
    public static class CDL2 implements Runnable{
        private final CountDownLatch cdl;
        private int startIndex;
        private int endIndex;
        
        CDL2(CountDownLatch cdl,int startIndex,int endIndex){
            this.cdl = cdl;
            this.startIndex = startIndex;
            this.endIndex = endIndex;
        }
        
        @Override
        public void run() {
            int num = 0;
            for (int i = startIndex; i < endIndex; i++) {
                num +=1;
            }
            result.add(num);
            cdl.countDown();
        }
    }
    
    public static void mainCDL2(){
        long startTime = System.currentTimeMillis();
        CountDownLatch cdl = new CountDownLatch(5);
        try {
            result.clear();
            int index = 100000000;
            
            for (int i = 1; i <=5; i++) {
                int num = index*i;
                new Thread(new CDL2(cdl, num-index, num)).start();;
            }
            cdl.await();
            sum();
            System.out.println("计算耗时为: "+(System.currentTimeMillis()-startTime));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    /**@className:Test2.java
    
     * @description:CyclicBarrier 实现计算
    
     * @date 2014年10月9日 上午10:31:03
     */
    public static class CB{
        
         int N;
         final CyclicBarrier cb;
        
         class Worker implements Runnable{
            int myRows;
            
            Worker(int row){
                this.myRows = row;
            }
            
            @Override
            public void run() {
                System.out.println(myRows+" 当前线程计算结束: "+Thread.currentThread().getName());
                try {
                    cb.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }
            
         }
        
         CB(){
             cb = new CyclicBarrier(5, new Runnable() {
                
                @Override
                public void run() {
                    System.out.println("当前线程为: "+Thread.currentThread().getName());
                    System.out.println("计算的总和为: "+1000);
                }
            });
            
             for (int i = 0; i < 5; i++) {
                new Thread(new Worker(i)).start();
            }
            
         }
        
        
    }
    
    public static void main(String[] args) throws InterruptedException{
        //mainCDL();
        
//        for (int i = 0; i < 10; i++) {
//            mainCDL2();
//            new Test().cal();
//        }
        
        new CB();
        
    }
    
    static void dosomethingElse(){
        System.out.println("要做点啥呢!");
    }
    
    static void sum(){
        int sum = 0;
        for (int i = 0; i < result.size(); i++) {
            sum += result.get(i);
        }
        System.out.println("计算总和为:"+sum);
    }
}

 

 

java 同步之CountDownLatch、CyclicBarrier

  • 0

    开心

    开心

  • 0

    板砖

    板砖

  • 0

    感动

    感动

  • 0

    有用

    有用

  • 0

    疑问

    疑问

  • 0

    难过

    难过

  • 0

    无聊

    无聊

  • 0

    震惊

    震惊

编辑推荐
前面写了两篇JDBC源码的文章,自己都觉得有点枯燥,先插一段JUC系列的文章来换换胃口,前面有文章大
1.CountDownLatch -- 锁存器 有时在线程开发中遇到一些问题,如主线程启动了多个子线程,主线程需要
package com.entel.research; import java.util.concurrent.CyclicBarrier; import java.util.concu
CyclicBarrier一个同步辅助类。 它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier
CountDownLatch 犹如倒计时计数器,调用CountDownLatch对象的countDown方法就将计数器减1,当计数到
允许一系列的集合等待彼此,到达一个共同的障碍物点. 表示大家彼此等待,大家集合好后才开始出发,分散
一.概述 使用JAVA编写并发程序的时候,我们需要仔细去思考一下并发流程的控制,如何让各个线程之间协
详细代码如下: public class CountdownLatchTest { public static void main(String[] args) { Exec
现实场景下我们可以借助java.util.concurrent包下的以下几个类做到更好。 1.CountDownLatch(闭锁) 2
CountDownLatch位于java.util.concurrent包下,是JDK1.5的并发包下的新特性。 首先根据Oracle的官方
版权所有 IT知识库 CopyRight © 2009-2015 IT知识库 IT610.com , All Rights Reserved. 京ICP备09083238号