zoukankan      html  css  js  c++  java
  • Java并发编程-CountDownLatch&CyclicBarrier

    1、CountDownLatch和CyclicBarrier作用

      CountDownLatch和CyclicBarrier都位于java.util.concurrent包中,都具有计数功能,一般用于多线程间的协作。

      CountDownLatch是减法计数器,子线程中调用countDown()计数减1,主线程调用await()阻塞线程执行,直到计数为0才会让线程继续执行,CountDownLatch不可重复利用。

      CyclicBarrier是加法计数器,子线程调用await()计数加1,同时阻塞线程执行,直到兄弟线程都执行了await(),计数到达了设定值,CyclicBarrier可重复使用,计数到达指定值后重新开始。CyclicBarrier构造函数设定一个Runnable参数,通知计数已到达指定值。

    2、使用示例

    package com.zhi.test;
    
    import java.util.Random;
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.CyclicBarrier;
    
    import org.junit.Test;
    
    /**
     * CyclicBarrier和CountDownLatch使用样例
     * 
     * @author 张远志
     * @since 2020年5月4日18:01:00
     *
     */
    public class MyTest {
        @Test
        public void test() {
            int jobCount = 5;
            CountDownLatch latch = new CountDownLatch(jobCount);
            CyclicBarrier barrier = new CyclicBarrier(jobCount, new Runnable() {
                public void run() {
                    System.out.println("所有线程都到了");
                }
            });
            for (int i = 1; i <= jobCount; i++) {
                new Thread(new Job(latch, barrier, i)).start();
            }
            try {
                latch.await();
            } catch (Exception e) {
            }
            System.out.println("所有线程已执行完成!");
        }
    
        class Job implements Runnable {
            private CountDownLatch latch;
            private CyclicBarrier barrier;
            private final int id;
    
            public Job(CountDownLatch latch, CyclicBarrier barrier, int id) {
                this.latch = latch;
                this.barrier = barrier;
                this.id = id;
            }
    
            @Override
            public void run() {
                try {
                    Thread.sleep(new Random().nextInt(10) * 1000);
                    System.out.println("线程" + id + "到达栅栏1");
                    barrier.await();
                } catch (Exception e) {
                }
                try {
                    System.out.println("线程" + id + "到达栅栏2");
                    barrier.await();
                } catch (Exception e) {
                }
                System.out.println("任务" + id + "执行完成");
                latch.countDown();
            }
        }
    }

      执行结果:

    线程2到达栅栏1
    线程4到达栅栏1
    线程5到达栅栏1
    线程3到达栅栏1
    线程1到达栅栏1
    所有线程都到了
    线程1到达栅栏2
    线程2到达栅栏2
    线程5到达栅栏2
    线程4到达栅栏2
    线程3到达栅栏2
    所有线程都到了
    任务3执行完成
    任务1执行完成
    任务2执行完成
    任务4执行完成
    任务5执行完成
    所有线程已执行完成!

    3、如何保证计数的线程安全性

      CountDownLatch的countDown会进行加法计数,CyclicBarrier的await()会进行加法计数,查看源码我们会发现,这2个方法都没有使用synchronized关键字,那他们有时如何保证线程安全性的呢?

      查看CountDownLatch源码,我们看到CountDownLatch使用了Sync内部类(继承AbstractQueuedSynchronizer)做减法,通过Unsafe类比较并设置新值。

      查看CyclicBarrier源码,我们看到ReentrantLock锁。为啥它与CountDownLatch不一样呢,因为CyclicBarrier不仅要完成计数,还需要调用barrierCommand,并且要实现重复可用(将count值还原),其实ReentrantLock内部也使用Unsafe类进行了原子操作。

  • 相关阅读:
    20080619 SQL SERVER 输入 NULL 的快捷键
    20090406 Adobe的“此产品的许可已停止工作”错误的解决办法
    20080908 Office Powerpoint 2007 不能输入中文的解决办法
    20080831 ClearGertrude Blog Skin 's cnblogs_code class
    20080603 Facebook 平台正式开放
    20080519 安装 Microsoft SQL Server 2000 时提示 创建挂起的文件操作
    test
    Linux—fork函数学习笔记
    SOA的设计理念
    Why BCP connects to SQL Server instance which start with account of Network Service fail?
  • 原文地址:https://www.cnblogs.com/zhi-leaf/p/10275334.html
Copyright © 2011-2022 走看看