Java併發包中CountDownLatch和CyclicBarrier的區別

CountDownLatch

CountDownLatch一般用於一個線程等待多個線程完成操作,

@Slf4j
public class CountDownLatchExample1 {

    private final static int threadCount = 200;

//    private static Logger log = LoggerFactory.getLogger(CountDownLatchExample1.class);

    public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newCachedThreadPool();
        final CountDownLatch countDownLatch =  new CountDownLatch(threadCount);
        for (int i = 0; i < threadCount; i++) {
            final int threadNum = i;
            executorService.execute(
                    ()->{
                        try {
                            test(threadNum);
                        }
                        catch (Exception e){
                            log.error("exception",e);
                        }
                        finally {
                            countDownLatch.countDown();
                        }
                    }
            );
        }
        countDownLatch.await();
        log.info("finish");
        executorService.shutdown();
    }

    private static void test(int threadNum) throws Exception {
        Thread.sleep(100);
        log.info("{}", threadNum);
        Thread.sleep(100);
    }
}

這裏的主線程將等待200個工作線程都完成工作後再繼續執行,並關閉線程池。

CyclicBarrier

CyclicBarrier用於多個線程都到達某個狀態後,所有等待線程再繼續執行。CyclicBarrier可以用於多線程計算數據,最後合併計算結果的場景。例如,用一個Excel保存了用戶所有銀行流水,每個Sheet保存一個賬戶近一年的每筆銀行流水,現在需要統計用戶的日均銀行流水,先用多個線程處理每個sheet裏的銀行流水,都執行完之後,得到每個sheet的日均銀行流水,最後,再用barrierAction用這些線程的計算結果,計算出整個Excel的日均銀行流水。

public class BankWaterService implements Runnable{
    private CyclicBarrier barrier = new CyclicBarrier(4,this);
    private CountDownLatch countDownLatch = new CountDownLatch(4);
    private ExecutorService threadPool = Executors.newFixedThreadPool(4);

    private ConcurrentHashMap<String,Integer> sheetBankCount = new ConcurrentHashMap<>();

    public void count() throws InterruptedException {
        for (int i = 0; i <4 ; i++) {
            threadPool.execute(()->{
                sheetBankCount.put(Thread.currentThread().getName(),1);
                try {
                    System.out.println(Thread.currentThread().getName()+" wait");
                    barrier.await();
                    System.out.println(Thread.currentThread().getName()+" continue " + "final result: "+sheetBankCount.get("result"));
                    countDownLatch.countDown();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            });
        }
        countDownLatch.await();
        threadPool.shutdown();
    }

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

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

這裏每一個工作線程將自己的計算結果放入ConcurrentHashMap中就進入等待,當所有工作線程都進入等待後,CyclicBarrier到達屏障,將調用回調方法,這裏的回調方法就是this的run方法。之後所有工作線程被喚醒。CountDownLatch用於等待所有工作線程結束後關閉線程池。

"C:\Program Files\Java\jdk1.8.0_221\bin\java.exe" "-javaagent:C:\Development\Intellij Idea\IntelliJ IDEA 2018.2.8\lib\idea_rt.jar=55458:C:\Development\Intellij Idea\IntelliJ IDEA 2018.2.8\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_221\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\rt.jar;C:\Development\java projects\Concurrency\target\classes;C:\Development\maven\Repo\org\springframework\boot\spring-boot-starter-web\1.5.9.RELEASE\spring-boot-starter-web-1.5.9.RELEASE.jar;C:\Development\maven\Repo\org\springframework\boot\spring-boot-starter\1.5.9.RELEASE\spring-boot-starter-1.5.9.RELEASE.jar;C:\Development\maven\Repo\org\springframework\boot\spring-boot\1.5.9.RELEASE\spring-boot-1.5.9.RELEASE.jar;C:\Development\maven\Repo\org\springframework\boot\spring-boot-autoconfigure\1.5.9.RELEASE\spring-boot-autoconfigure-1.5.9.RELEASE.jar;C:\Development\maven\Repo\org\springframework\boot\spring-boot-starter-logging\1.5.9.RELEASE\spring-boot-starter-logging-1.5.9.RELEASE.jar;C:\Development\maven\Repo\ch\qos\logback\logback-classic\1.1.11\logback-classic-1.1.11.jar;C:\Development\maven\Repo\ch\qos\logback\logback-core\1.1.11\logback-core-1.1.11.jar;C:\Development\maven\Repo\org\slf4j\jcl-over-slf4j\1.7.25\jcl-over-slf4j-1.7.25.jar;C:\Development\maven\Repo\org\slf4j\jul-to-slf4j\1.7.25\jul-to-slf4j-1.7.25.jar;C:\Development\maven\Repo\org\slf4j\log4j-over-slf4j\1.7.25\log4j-over-slf4j-1.7.25.jar;C:\Development\maven\Repo\org\yaml\snakeyaml\1.17\snakeyaml-1.17.jar;C:\Development\maven\Repo\org\springframework\boot\spring-boot-starter-tomcat\1.5.9.RELEASE\spring-boot-starter-tomcat-1.5.9.RELEASE.jar;C:\Development\maven\Repo\org\apache\tomcat\embed\tomcat-embed-core\8.5.23\tomcat-embed-core-8.5.23.jar;C:\Development\maven\Repo\org\apache\tomcat\tomcat-annotations-api\8.5.23\tomcat-annotations-api-8.5.23.jar;C:\Development\maven\Repo\org\apache\tomcat\embed\tomcat-embed-el\8.5.23\tomcat-embed-el-8.5.23.jar;C:\Development\maven\Repo\org\apache\tomcat\embed\tomcat-embed-websocket\8.5.23\tomcat-embed-websocket-8.5.23.jar;C:\Development\maven\Repo\org\hibernate\hibernate-validator\5.3.6.Final\hibernate-validator-5.3.6.Final.jar;C:\Development\maven\Repo\javax\validation\validation-api\1.1.0.Final\validation-api-1.1.0.Final.jar;C:\Development\maven\Repo\org\jboss\logging\jboss-logging\3.3.1.Final\jboss-logging-3.3.1.Final.jar;C:\Development\maven\Repo\com\fasterxml\classmate\1.3.4\classmate-1.3.4.jar;C:\Development\maven\Repo\com\fasterxml\jackson\core\jackson-databind\2.8.10\jackson-databind-2.8.10.jar;C:\Development\maven\Repo\com\fasterxml\jackson\core\jackson-annotations\2.8.0\jackson-annotations-2.8.0.jar;C:\Development\maven\Repo\com\fasterxml\jackson\core\jackson-core\2.8.10\jackson-core-2.8.10.jar;C:\Development\maven\Repo\org\springframework\spring-web\4.3.13.RELEASE\spring-web-4.3.13.RELEASE.jar;C:\Development\maven\Repo\org\springframework\spring-aop\4.3.13.RELEASE\spring-aop-4.3.13.RELEASE.jar;C:\Development\maven\Repo\org\springframework\spring-beans\4.3.13.RELEASE\spring-beans-4.3.13.RELEASE.jar;C:\Development\maven\Repo\org\springframework\spring-context\4.3.13.RELEASE\spring-context-4.3.13.RELEASE.jar;C:\Development\maven\Repo\org\springframework\spring-webmvc\4.3.13.RELEASE\spring-webmvc-4.3.13.RELEASE.jar;C:\Development\maven\Repo\org\springframework\spring-expression\4.3.13.RELEASE\spring-expression-4.3.13.RELEASE.jar;C:\Development\maven\Repo\org\slf4j\slf4j-api\1.7.25\slf4j-api-1.7.25.jar;C:\Development\maven\Repo\org\springframework\spring-core\4.3.13.RELEASE\spring-core-4.3.13.RELEASE.jar;C:\Development\maven\Repo\org\projectlombok\lombok\1.16.10\lombok-1.16.10.jar;C:\Development\maven\Repo\com\google\guava\guava\23.0\guava-23.0.jar;C:\Development\maven\Repo\com\google\code\findbugs\jsr305\1.3.9\jsr305-1.3.9.jar;C:\Development\maven\Repo\com\google\errorprone\error_prone_annotations\2.0.18\error_prone_annotations-2.0.18.jar;C:\Development\maven\Repo\com\google\j2objc\j2objc-annotations\1.1\j2objc-annotations-1.1.jar;C:\Development\maven\Repo\org\codehaus\mojo\animal-sniffer-annotations\1.14\animal-sniffer-annotations-1.14.jar;C:\Development\maven\Repo\joda-time\joda-time\2.9\joda-time-2.9.jar;C:\Development\maven\Repo\redis\clients\jedis\2.8.2\jedis-2.8.2.jar;C:\Development\maven\Repo\org\apache\commons\commons-pool2\2.4.3\commons-pool2-2.4.3.jar" com.mmall.concurrency.threadTest.cyclicBarrier.BankWaterService
pool-1-thread-1 wait
pool-1-thread-4 wait
pool-1-thread-2 wait
pool-1-thread-3 wait
result: 4
pool-1-thread-3 continue final result: 4
pool-1-thread-1 continue final result: 4
pool-1-thread-4 continue final result: 4
pool-1-thread-2 continue final result: 4

Process finished with exit code 0

可以看到每個工作線程完成自己的計算任務,把它加入到ConcurrentHashMap後就進入等待,等4個工作線程都到達屏障後,調用回調方法,再喚醒所有線程。最後關閉線程池。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章