CountDownLatch和CyclicBarrier分析

CountDownLatch几个经常用的方法分析

CountDownLatch构造函数
    public CountDownLatch(int count) {
        if (count < 0) throw new 
        IllegalArgumentException("count < 0");
        //此处调用CountDownLatch的队列同步器
        this.sync = new Sync(count);
    }
    
    //设置state
    Sync(int count) {
        setState(count);
    }
CountDownLatch的await()
/**
     * Causes the current thread to wait until the latch has counted down to
     * zero, unless the thread is {@linkplain Thread#interrupt interrupted}.
     *
     * <p>If the current count is zero then this method returns immediately.
     *
     * <p>If the current count is greater than zero then the current
     * thread becomes disabled for thread scheduling purposes and lies
     * dormant until one of two things happen:
     */
     //上面翻译大意是:当前线程等待直到state到0时
     //除非被打断
    public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }
    //调用模板方法中的tryAcquireShared(arg)
    public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
    }
    //当获取到state是否等于0,返回1或者-1
     protected int tryAcquireShared(int acquires) {
            return (getState() == 0) ? 1 : -1;
        }
CountDownLatch中的countDown()
 /**
     * Decrements the count of the latch, releasing all waiting threads if
     * the count reaches zero.
     *
     * <p>If the current count is greater than zero then it is decremented.
     * If the new count is zero then all waiting threads are re-enabled for
     * thread scheduling purposes.
     *
     * <p>If the current count equals zero then nothing happens.
     */
     //减少state数量,如果到达0,释放所有正在等待的线程
    public void countDown() {
        sync.releaseShared(1);
    }
     public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {
            doReleaseShared();
            return true;
        }
        return false;
    }
    //这是CountDownLatch类型重写的模板方法
     protected boolean tryReleaseShared(int releases) {
            // Decrement count; signal when transition to zero
            for (;;) {
                int c = getState();
                if (c == 0)
                    return false;
                int nextc = c-1;
                if (compareAndSetState(c, nextc))
                    //只有等于0的时候才会返回true
                    return nextc == 0;
            }
        }
    
CountDownLatch的官方示例
* class Driver2 { // ...
 *   void main() throws InterruptedException {
 *     CountDownLatch doneSignal = new CountDownLatch(N);
 *     Executor e = ...
 *
 *     for (int i = 0; i < N; ++i) // create and start threads
 *       e.execute(new WorkerRunnable(doneSignal, i));
 *
 *     doneSignal.await();           // wait for all to finish
 *   }
 * }
 *
 * class WorkerRunnable implements Runnable {
 *   private final CountDownLatch doneSignal;
 *   private final int i;
 *   WorkerRunnable(CountDownLatch doneSignal, int i) {
 *     this.doneSignal = doneSignal;
 *     this.i = i;
 *   }
 *   public void run() {
 *     try {
 *       doWork(i);
 *       doneSignal.countDown();
 *     } catch (InterruptedException ex) {} // return;
 *   }
 *
 *   void doWork() { ... }
 * }}</pre>
 *
原理

构造函数N,调用await()开始,知道countDown()N次,才会继续执行后续操作
具体原理,就是await()也就是lock()当前线程,(上述的例子中是main线程),后面会调用
countDown()N次,才会unlock()当前线程

CyclicBarrier例子

同时计算N个示例,计算完N个示例,执行runnable里面的run()方法
import java.util.Map;
import java.util.concurrent.*;
public class BankWaterService implements Runnable{
    //创建4个屏障,处理完之后执行当前类的run方法
    private CyclicBarrier cyclicBarrier = new CyclicBarrier(4,this);
    //假如只有4个sheet,所以启动4个线程
    private ExecutorService executor = Executors.newFixedThreadPool(4);
    private ConcurrentHashMap<String,Integer> sheetBankWaterCount = new ConcurrentHashMap<String,Integer>();
    private void count(){
        try {
            for (int i = 0; i < 4; i++) {
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        //计算当前i对应的sheet的银流数据,计算代码省略
                        try {
                            TimeUnit.SECONDS.sleep(1);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        sheetBankWaterCount.put(Thread.currentThread().getName(), 1);
                        //银流计算完成,插入一个屏障
                        try {
                            cyclicBarrier.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        } catch (BrokenBarrierException e) {
                            e.printStackTrace();
                        }
                    }
                });
            }
        }finally {
            executor.shutdown();
        }
    }

    @Override
    public void run(){
        int result = 0;
        for(Map.Entry<String,Integer> sheet : sheetBankWaterCount.entrySet()){
            result += sheet.getValue();
        }
        System.out.println(result);

    }

    public static void main(String[] args) {
        BankWaterService bankWaterService = new BankWaterService();
        bankWaterService.count();
    }
}

上述代码,是为了执行计算多个sheet中的数据,最后执行合计

来测试runnable到底是最先执行还是最后执行
public class CyclicBarrierTest2 {
    static CyclicBarrier cyclicBarrier = new CyclicBarrier(2,new A());

    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
                System.out.println(1);
            }
        }).start();
        try {
            cyclicBarrier.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
        System.out.println(2);
    }

    static class A implements Runnable{

        @Override
        public void run() {
            System.out.println(3);
        }
    }

}
//输出结果
3
1 
2
源码分析

要知道源码中调用的是ReentrantLock可重入式锁

 /**
     * Main barrier code, covering the various policies.
     */
    private int dowait(boolean timed, long nanos)
        throws InterruptedException, BrokenBarrierException,
               TimeoutException {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            final Generation g = generation;

            if (g.broken)
                throw new BrokenBarrierException();

            if (Thread.interrupted()) {
                breakBarrier();
                throw new InterruptedException();
            }

            int index = --count;
            //可以看到,执行了多个await()之后,导致count==0时,才会执行下面代码
            if (index == 0) {  // tripped
                boolean ranAction = false;
                try {
                    final Runnable command = barrierCommand;
                    if (command != null)
                        //这个地方最搞笑的是他直接run了。
                        command.run();
                    ranAction = true;
                    //此处是为下一波僵尸来临做准备
                    nextGeneration();
                    return 0;
                } finally {
                    if (!ranAction)
                        breakBarrier();
                }
            }

            // loop until tripped, broken, interrupted, or timed out
            for (;;) {
                try {
                    if (!timed)
                        trip.await();
                    else if (nanos > 0L)
                        nanos = trip.awaitNanos(nanos);
                } catch (InterruptedException ie) {
                    if (g == generation && ! g.broken) {
                        breakBarrier();
                        throw ie;
                    } else {
                        // We're about to finish waiting even if we had not
                        // been interrupted, so this interrupt is deemed to
                        // "belong" to subsequent execution.
                        Thread.currentThread().interrupt();
                    }
                }

                if (g.broken)
                    throw new BrokenBarrierException();

                if (g != generation)
                    return index;

                if (timed && nanos <= 0L) {
                    breakBarrier();
                    throw new TimeoutException();
                }
            }
        } finally {
            lock.unlock();
        }
    }
        /**
     * Updates state on barrier trip and wakes up everyone.
     * Called only while holding lock.
     */
    private void nextGeneration() {
        // signal completion of last generation
        trip.signalAll();
        // set up next generation
        //重新给count赋了值,parties也就是构造函数里面的值
        count = parties;
        generation = new Generation();
    }
await()这个考虑更多的是,你的线程业务执行完后,再调用await()才好执行。直到执行到最后一个,才会正在的unlock();
展示一波,cyclicBarrier重用
public class CyclicBarrierTest3 {

    static class Writer extends Thread{
        private CyclicBarrier cyclicBarrier;
        public Writer(CyclicBarrier cyclicBarrier){
            this.cyclicBarrier = cyclicBarrier;
        }

        @Override
        public void run() {
            System.out.println("线程" + Thread.currentThread().getName() + "正在写入数据...");
            try {
                Thread.sleep(5000);
                System.out.println("线程" + Thread.currentThread().getName() + "写入数据完毕,等待其他线程写入");
                cyclicBarrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }catch (BrokenBarrierException e){
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "所有线程写入完毕,继续处理其他任务");
        }
    }

    public static void main(String[] args) {
        int N = 4;
        CyclicBarrier cyclicBarrier = new CyclicBarrier(N);
        for(int i = 0 ;i < N ;i++){
            new Writer(cyclicBarrier).start();
        }
        try {
            Thread.sleep(25000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Cyclicbarrier重用");
        for(int i = 0 ;i < N ;i++){
            new Writer(cyclicBarrier).start();
        }
    }
}
//输出结果
线程Thread-0正在写入数据...
线程Thread-2正在写入数据...
线程Thread-1正在写入数据...
线程Thread-3正在写入数据...
线程Thread-2写入数据完毕,等待其他线程写入
线程Thread-0写入数据完毕,等待其他线程写入
线程Thread-1写入数据完毕,等待其他线程写入
线程Thread-3写入数据完毕,等待其他线程写入
Thread-2所有线程写入完毕,继续处理其他任务
Thread-1所有线程写入完毕,继续处理其他任务
Thread-3所有线程写入完毕,继续处理其他任务
Thread-0所有线程写入完毕,继续处理其他任务
Cyclicbarrier重用
线程Thread-4正在写入数据...
线程Thread-5正在写入数据...
线程Thread-6正在写入数据...
线程Thread-7正在写入数据...
线程Thread-4写入数据完毕,等待其他线程写入
线程Thread-6写入数据完毕,等待其他线程写入
线程Thread-7写入数据完毕,等待其他线程写入
线程Thread-5写入数据完毕,等待其他线程写入
Thread-5所有线程写入完毕,继续处理其他任务
Thread-4所有线程写入完毕,继续处理其他任务
Thread-6所有线程写入完毕,继续处理其他任务
Thread-7所有线程写入完毕,继续处理其他任务

部分示例来自海子的博客

还有部分代码来自:《java并发编程的艺术》

不知之处,欢迎大家留言

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值