CyclicBarrier和CountDownLatch的區別


 CountDownLatch

Countdownlatch是一個同步工具類;用來協調多個線程之間的同步;

這個工具通常用來控制線程等待;它可以讓某一個線程等待知道倒計時結束,在開始執行;

CountDownLatch的兩種用法:

1. 某一線程在開始運行前等待n個線程執行完畢;將CountDownLatch的計數器初始化為n:new CountDownLatch(n);每當一個任務線程執行完畢,就將計數器減1,CountDownLatch.Countdown;當計數器的值變為0時;在CountDownLatch上await()的線程就會被喚醒。一個典型應用場景就是啟動一個服務時,主線程需要等待多個組件加載完畢;

2. 實現多個線程開始執行任務的最大並行性;注意是並行性;而不是並發性;強調的是多個線程在某一時刻同時執行,類似於賽跑;將多個線程放到起點;等待發令槍響;然后同時開跑;做法是初始化一個共享的CountDownLatch對象;將其計數器初始化為1:new CountdownLatch(1);多個線程在開始執行任務前首先CountDownLatch.await(),當主線程調用countdownl時,計數器變為0;多個線程同時被喚醒;

package com.practice.test;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CountDownLatchExample1 {
    public static final int threadCount = 550;

    public static void main(String[] args) throws InterruptedException {
        ExecutorService threadpool = Executors.newFixedThreadPool(300);
        final CountDownLatch cl = new CountDownLatch(threadCount);
        for (int i = 0; i < threadCount; i++) {
            final int threadnum = i;
            threadpool.execute(() -> {
                try {
                    test(threadnum);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } finally {
                    cl.countDown();
                }
            });
        }
        cl.await();
        threadpool.shutdown();
        System.out.println("finish");
    }

    public static void test(int threadnum) throws InterruptedException {
        Thread.sleep(1000);
        System.out.println("threadnum" + threadnum);
        Thread.sleep(1000);
    }

}

 

3. Countdownlatch的不足

Countdownlatch是一次性的,計數器的值只能在構造方法中初始化一次,之后沒有任何機制再次對其設置值,當CountDownLatch使用完畢后,他不能再次被使用

CyclicBarrier

CyclicBarrier和CountDownLatch非常類似,他也可以實現線程間的技術等待,但是它的功能比CountDownLatch更加強大和復雜。主要應用場景和CountDownLatch類似

CyclicBarrier的字面意思是可循環使用的屏障,它要做的事情是,讓一組線程到達一個屏障時被阻塞,直到最后一個線程到達屏障時,屏障才會開門,所有被屏障攔截的線程才會繼續干活。CyclicBarrier默認的構造方法時CyclicBarrier(int parties),其參數表示屏障攔截的線程數量,每個線程調用await方法告訴CyclicBarrier我已經到達了屏障。然后當前線程被阻塞;

package com.practice.test;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class CyclicBarrierExample2 {
    private static final int threadcount = 550;
    private static final CyclicBarrier cyb = new CyclicBarrier(5);

    public static void main(String[] args) throws InterruptedException {
        ExecutorService threadpool = Executors.newFixedThreadPool(10);
        for (int i = 0; i < threadcount; i++) {
            final int num = i;
            Thread.sleep(1000);
            threadpool.execute(() -> {
                try {
                    try {
                        test(num);
                    } catch (TimeoutException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            });
        }
        threadpool.shutdown();
    }

    public static void test(int threadnum) throws InterruptedException, BrokenBarrierException, TimeoutException {
        System.out.println("threadnum" + threadnum + "is ready");
        try {
        cyb.await(2000, TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            System.out.println("CyclicBarrier");
        }
        System.out.println("threadnum" + threadnum + "isFinish");
    }
}

 

CyclicBarrier的應用場景

CyclicBarrier可以用於多線程計算數據,最后合並結果的應用場景。比如我們用一個Excel保存了用戶所有銀行流水,每個Sheet保存每一個賬戶近一年的每一筆銀行流水,現在需要統計用戶的日均銀行流水,先用多線程處理每個sheet里的銀行流水,都執行完之后,得到每個sheet的日均銀行流水,最后,使用barrierAction用這些線程的計算結果,計算出整個Excel的日均銀行流水;

CyclicBarrier(int parties,Runnable BarrierAction),在線程到達屏障時,優先執行BarrierAction,方便處理更復雜的業務場景;

package com.practice.test;

import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierTest {
    public static void main(String[] args) {
        CyclicBarrier cyl = new CyclicBarrier(5, () -> {
            System.out.println("線程組執行結束");

        });
        for (int i = 0; i < 5; i++) {
            new Thread(new Readnum(i, cyl)).start();
        }
    }

    static class Readnum implements Runnable {
        private int id;
        private CyclicBarrier cdl;

        public Readnum(int id, CyclicBarrier cdl) {
            super();
            this.id = id;
            this.cdl = cdl;
        }

        @Override
        public void run() {
            synchronized (this) {
                System.out.println(Thread.currentThread().getName() + "id");
                try {
                    cdl.await();
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + id + "結束了");

            }
        }
    }
}

 

CyclicBarrier和CountDownLatch的區別

CountDownLatch是計數器,只能使用一次,而CyclicBarrier的計數器提供reset功能,可以多次使用,

JavaDoc中的定義:

CountDownLatch:一個或者多個線程,等待其他線程完成某件事情之后,等待其他多個線程完成某件事情之后才能執行;

CyclicBarrier:多個線程互相等待,直到到達同一個同步點,再繼續一起執行;

對於CountDownLatch來說,重點是一個線程(多個線程)等待”,而其他的N個線程在完成”某件事情“之后,可以終止,也可以等待,而對於CyclicBarrier,重點是多個線程,在任意一個線程沒有完成,所有的線程都必須等待;

CountDownLatch是計數器,線程完成一個記錄一個,只不過計數不是遞增而是遞減,而CyclicBarrier更像是一個閥門,需要所有線程都要到達,閥門才能打開,然后繼續執行;

 

文章參考自:

https://github.com/Snailclimb

https://blog.csdn.net/tolcf/article/details/50925145?utm_source=blogxgwz0


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM