CyclicBarrier與CountDownLatch區別

阻塞與喚醒方式的區別

CountDownLatch計數方式

CountDownLatch是減計數。調用await()後線程阻塞。調用countDown()方法後計數減一,當計數爲零時,調用await()的線程被喚醒。

CountDownLatch應用場景爲:

一個或一組線程等待另一組線程完成操作後恢復執行

CountDownLatch例子: 模擬賽跑

開始時一組運動員線程等待begin計數器(初始值爲1),當主線程調用begin.countDown()後begin減1,計數器爲0,這一組運動員線程同時起跑。主線程等待end計數器(初始值爲10)。一個運動員線程到達終點後,調用end.countDown(),end計數器減1。當所有運動員都到達終點後,end計數器爲0,主線程恢復執行。

package CountDownLatch;

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

public class RaceSimulation {
    public static void main(String args[]){
        //比賽開始的倒數鎖
        CountDownLatch begin=new CountDownLatch(1);
        //比賽結束的倒數鎖
        CountDownLatch end=new CountDownLatch(10);
        //十個選手跑步線程
        final ExecutorService exec = Executors.newFixedThreadPool(10);

        for(int index= 0;index<10;++index){
            final int NO=index+1;
            Runnable run = new Runnable(){
                @Override
                public void run() {
                    try{
                        //如果計數不爲0,則一直等待
                        //如果當前計數爲0,此線程立即執行
                        begin.await();
                        Thread.sleep((long)(Math.random()*10000));
                        System.out.println("No."+NO+" arrived");
                    }catch(InterruptedException e){
                        e.printStackTrace();
                    }finally{
                        //每個選手到達終點時,end就減1
                        end.countDown();
                    }
                }
            };
            exec.submit(run);
        }
        System.out.println("遊戲開始:");
        //begin減1,開始遊戲
        begin.countDown();
        //等待end變爲0,即所有選手到達終點
        try {
            end.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("遊戲結束");
        exec.shutdown();
    }
}

CyclicBarrier計數方式

CyclicBarrier是加計數。調用await()後線程阻塞計數器加1,當所有線程都到達屏障被阻塞後,這一組線程才一起恢復執行。

CyclicBarrier的應用場景

一組線程到達一個屏障(即執行CyclicBarrier.await())時被阻塞,直到最後一個線程到達屏障時,屏障纔會開門,所有被屏障攔截的線程纔會繼續幹活。CyclicBarrier默認的構造方法是CyclicBarrier(int parties),其參數表示屏障攔截的線程數量,每個線程調用await方法告訴CyclicBarrier我已經到達了屏障,然後當前線程被阻塞。

CyclicBarier的例子

package cyclicBarrier;

import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CyclicBarrierDemo {
    public static void main(String[] args) {
        int N=4;
        CyclicBarrier cyclicBarrier=new CyclicBarrier(N,new Runnable() {
            @Override
            public void run() {
                System.out.println("線程"+Thread.currentThread().getName()+"正在執行所有線程到達屏障後執行的操作");
            }
        });
        ExecutorService exec=Executors.newFixedThreadPool(4);
        for(int i=0;i<N;++i) {
            Runnable r=()->{
                try {
                    System.out.println("線程"+Thread.currentThread().getName()+"正在執行線程的操作");
                    //用睡眠代替線程的操作
                    Thread.sleep(new Random().nextInt(1000));
                    System.out.println("線程"+Thread.currentThread().getName()+"到達屏障");
                    cyclicBarrier.await();
                    System.out.println("線程"+Thread.currentThread().getName()+"越過屏障,線程執行完畢");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
           };
           exec.submit(r);
        }
        exec.shutdown();
    }
}

是否可以重用

  1. CountDownLatch不可以重用

  2. CyclicBarrier可以重用

package cyclicBarrier;

import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CyclicBarrierDemo {
    public static void main(String[] args) {
        int N=4;
        CyclicBarrier cyclicBarrier=new CyclicBarrier(N,new Runnable() {
            @Override
            public void run() {
                System.out.println("線程"+Thread.currentThread().getName()+"正在執行所有線程到達屏障後執行的操作");
            }
        });
        ExecutorService exec1=Executors.newFixedThreadPool(4);
        for(int i=0;i<N;++i) {
            Runnable r=()->{
                try {
                    System.out.println("線程"+Thread.currentThread().getName()+"正在執行線程的操作");
                    //用睡眠代替線程的操作
                    Thread.sleep(new Random().nextInt(1000));
                    System.out.println("線程"+Thread.currentThread().getName()+"到達屏障");
                    cyclicBarrier.await();
                    System.out.println("線程"+Thread.currentThread().getName()+"越過屏障,線程執行完畢");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
           };
           exec1.submit(r);
        }
        exec1.shutdown();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("CyclicBarrier重用");
        ExecutorService exec2=Executors.newFixedThreadPool(4);

        for(int i=0;i<N;++i) {
            Runnable r=()->{
                try {
                    System.out.println("線程"+Thread.currentThread().getName()+"正在執行線程的操作");
                    //用睡眠代替線程的操作
                    Thread.sleep(new Random().nextInt(1000));
                    System.out.println("線程"+Thread.currentThread().getName()+"到達屏障");
                    cyclicBarrier.await();
                    System.out.println("線程"+Thread.currentThread().getName()+"越過屏障,線程執行完畢");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
           };
           exec2.submit(r);
        }
        exec2.shutdown();
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章