天天看點

Java閉鎖(CountDownLatch)和栅欄(CyclicBarrier)CountDownLatchCyclicBarrier

假設一場短跑比賽,使用多個線程代表每個運動員的狀态和比賽過程,需要每個運動員同時出發,列印出每個關鍵節點的時間作為參考:

CountDownLatch

來自API文檔

Java閉鎖(CountDownLatch)和栅欄(CyclicBarrier)CountDownLatchCyclicBarrier

所有方法

Modifier and Type Method and Description

void

await()

導緻目前線程等到鎖存器計數到零,除非線程是 interrupted 。

boolean

await(long timeout, TimeUnit unit)

使目前線程等待直到鎖存器計數到零為止,除非線程為 interrupted或指定的等待時間過去。

void

countDown()

減少鎖存器的計數,如果計數達到零,釋放所有等待的線程。

long

getCount()

傳回目前計數。

String

toString()

傳回一個辨別此鎖存器的字元串及其狀态。
package com.muyi;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.CountDownLatch;

/**
 * @Author: muyi
 * @Date: 2021/3/23 10:27
 */
public class Main {

    final static SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    public static void main(String[] args) throws InterruptedException
    {
        CountDownLatch startLatch = new CountDownLatch(1);//控制比賽協作
        CountDownLatch endLatch = new CountDownLatch(8);// 每個人的比賽程序

        Runner run1 = new Runner(1,startLatch, endLatch);
        Runner run2 = new Runner(2, startLatch,endLatch);
        Runner run3 = new Runner(3, startLatch,endLatch);
        Runner run4 = new Runner(4, startLatch,endLatch);
        Runner run5 = new Runner(5, startLatch,endLatch);
        Runner run6 = new Runner(6, startLatch,endLatch);
        Runner run7 = new Runner(7, startLatch,endLatch);
        Runner run8 = new Runner(8, startLatch,endLatch);

        run1.start();
        run2.start();
        run3.start();
        run4.start();
        run5.start();
        run6.start();
        run7.start();
        run8.start();

        System.out.println("3秒鐘預備!");
        Thread.sleep(3000);
        System.out.println("起跑!"+sdf.format(new Date()));
        startLatch.countDown(); //工作開始
        endLatch.await();// 等待所有勞工完成工作
        System.out.println("比賽完成 " + sdf.format(new Date()));
    }

    static class Runner extends Thread {
        int no;
        CountDownLatch startLatch;
        CountDownLatch endLatch;
        public Runner(int no, CountDownLatch startLatch,CountDownLatch endLatch) {
            this.no = no;
            this.startLatch=startLatch;
            this.endLatch = endLatch;
        }
        @Override
        public void run() {
            try {
                Random random = new Random(no);
                Integer runTime = random.nextInt(5000)*2;
                System.out.println("run "+no+"進入賽道,等待開始!預計用時:"+runTime+"ms");
                startLatch.await(); //等待開始工作時間
                System.out.println("run " + no + " 起跑時間 "+ sdf.format(new Date()));
                Thread.sleep(runTime);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println("run " + no + " 到達終點時間 " + sdf.format(new Date())+";剩餘完成比賽人:"+(endLatch.getCount()-1));
//                if(no == 1) {   // code1
                    endLatch.countDown();// 完成比賽,計數器減一
//                }
            }
        }
    }
}
// out
3秒鐘預備!
run 5進入賽道,等待開始!預計用時:8974ms
run 1進入賽道,等待開始!預計用時:7970ms
run 8進入賽道,等待開始!預計用時:4728ms
run 7進入賽道,等待開始!預計用時:8472ms
run 4進入賽道,等待開始!預計用時:3724ms
run 2進入賽道,等待開始!預計用時:2216ms
run 3進入賽道,等待開始!預計用時:7468ms
run 6進入賽道,等待開始!預計用時:3222ms
起跑!2021-04-14 14:58:01
run 5 起跑時間 2021-04-14 14:58:01
run 1 起跑時間 2021-04-14 14:58:01
run 8 起跑時間 2021-04-14 14:58:01
run 4 起跑時間 2021-04-14 14:58:01
run 7 起跑時間 2021-04-14 14:58:01
run 3 起跑時間 2021-04-14 14:58:01
run 6 起跑時間 2021-04-14 14:58:01
run 2 起跑時間 2021-04-14 14:58:01
run 2 到達終點時間 2021-04-14 14:58:03;剩餘完成比賽人:7
run 6 到達終點時間 2021-04-14 14:58:04;剩餘完成比賽人:6
run 4 到達終點時間 2021-04-14 14:58:05;剩餘完成比賽人:5
run 8 到達終點時間 2021-04-14 14:58:06;剩餘完成比賽人:4
run 3 到達終點時間 2021-04-14 14:58:08;剩餘完成比賽人:3
run 1 到達終點時間 2021-04-14 14:58:09;剩餘完成比賽人:2
run 7 到達終點時間 2021-04-14 14:58:09;剩餘完成比賽人:1
run 5 到達終點時間 2021-04-14 14:58:10;剩餘完成比賽人:0
比賽完成 2021-04-14 14:58:10
           

通過上面的輸入結果得到:所有人同時起步,且詳細記錄了比賽結束的時間;

如果放開注釋code1,發現比賽無法結束,因為隻有run1正式通知了裁判組完成了比賽(endLatch.countDown());

3秒鐘預備!
run 7進入賽道,等待開始!預計用時:8472ms
run 8進入賽道,等待開始!預計用時:4728ms
run 5進入賽道,等待開始!預計用時:8974ms
run 4進入賽道,等待開始!預計用時:3724ms
run 2進入賽道,等待開始!預計用時:2216ms
run 6進入賽道,等待開始!預計用時:3222ms
run 1進入賽道,等待開始!預計用時:7970ms
run 3進入賽道,等待開始!預計用時:7468ms
起跑!2021-04-14 14:59:10
run 8 起跑時間 2021-04-14 14:59:10
run 5 起跑時間 2021-04-14 14:59:10
run 7 起跑時間 2021-04-14 14:59:10
run 4 起跑時間 2021-04-14 14:59:10
run 2 起跑時間 2021-04-14 14:59:10
run 3 起跑時間 2021-04-14 14:59:10
run 1 起跑時間 2021-04-14 14:59:10
run 6 起跑時間 2021-04-14 14:59:10
run 2 到達終點時間 2021-04-14 14:59:12;剩餘完成比賽人:7
run 6 到達終點時間 2021-04-14 14:59:13;剩餘完成比賽人:7
run 4 到達終點時間 2021-04-14 14:59:13;剩餘完成比賽人:7
run 8 到達終點時間 2021-04-14 14:59:14;剩餘完成比賽人:7
run 3 到達終點時間 2021-04-14 14:59:17;剩餘完成比賽人:7
run 1 到達終點時間 2021-04-14 14:59:18;剩餘完成比賽人:7
run 7 到達終點時間 2021-04-14 14:59:18;剩餘完成比賽人:6
run 5 到達終點時間 2021-04-14 14:59:19;剩餘完成比賽人:6
           

CyclicBarrier

Java閉鎖(CountDownLatch)和栅欄(CyclicBarrier)CountDownLatchCyclicBarrier

所有方法

int

await()

等待所有 parties已經在這個障礙上調用了

await

int

await(long timeout, TimeUnit unit)

等待所有 parties已經在此屏障上調用

await

,或指定的等待時間過去。

int

getNumberWaiting()

傳回目前正在等待障礙的各方的數量。

int

getParties()

傳回旅行這個障礙所需的聚會數量。

boolean

isBroken()

查詢這個障礙是否處于破碎狀态。

void

reset()

将屏障重置為初始狀态。

CyclicBarrier有兩個構造方法:

CyclicBarrier(int parties)

建立一個新的 CyclicBarrier ,當給定數量的線程(線程)等待它時,它将跳閘,并且當屏障跳閘時不執行預定義的動作。

package com.muyi;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;

/**
 * @Author: muyi
 * @Date: 2021/3/23 10:27
 */
public class Main {

    final static SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    public static void main(String[] args) throws InterruptedException
    {

        CyclicBarrier cyclicBarrier = new CyclicBarrier(8);
        Runner run1 = new Runner(1, cyclicBarrier);
        Runner run2 = new Runner(2, cyclicBarrier);
        Runner run3 = new Runner(3, cyclicBarrier);
        Runner run4 = new Runner(4, cyclicBarrier);
        Runner run5 = new Runner(5, cyclicBarrier);
        Runner run6 = new Runner(6, cyclicBarrier);
        Runner run7 = new Runner(7, cyclicBarrier);
        Runner run8 = new Runner(8, cyclicBarrier);

        run1.start();
        run2.start();
        run3.start();
        run4.start();
        run5.start();
        run6.start();
        run7.start();
        run8.start();
    }

    static class Runner extends Thread {
        int no;
        CyclicBarrier cyclicBarrier;
        public Runner(int no, CyclicBarrier cyclicBarrier) {
            this.no = no;
            this.cyclicBarrier=cyclicBarrier;
        }
        @Override
        public void run() {
            try {
                Random random = new Random(no);
                Integer runTime = random.nextInt(5000)*2;
                Thread.sleep(runTime/10);// 放大線程準備時間
                System.out.println("run "+no+"進入賽道,等待開始!預計用時:"+runTime+"ms,準備完成人數:"+(cyclicBarrier.getNumberWaiting()+1));
                cyclicBarrier.await();
                System.out.println("run " + no + " 起跑時間 "+ sdf.format(new Date()));
                Thread.sleep(runTime);
                System.out.println("run " + no + " 預計到達終點時間 " + sdf.format(new Date())+";完成比賽人數:"+(cyclicBarrier.getNumberWaiting()+1));
                cyclicBarrier.await();
                System.out.println("全部完成 " + sdf.format(new Date()));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

// out
run 2進入賽道,等待開始!預計用時:2216ms,準備完成人數:1
run 6進入賽道,等待開始!預計用時:3222ms,準備完成人數:2
run 4進入賽道,等待開始!預計用時:3724ms,準備完成人數:3
run 8進入賽道,等待開始!預計用時:4728ms,準備完成人數:4
run 3進入賽道,等待開始!預計用時:7468ms,準備完成人數:5
run 1進入賽道,等待開始!預計用時:7970ms,準備完成人數:6
run 7進入賽道,等待開始!預計用時:8472ms,準備完成人數:7
run 5進入賽道,等待開始!預計用時:8974ms,準備完成人數:8
run 1 起跑時間 2021-04-14 14:53:31
run 2 起跑時間 2021-04-14 14:53:31
run 4 起跑時間 2021-04-14 14:53:31
run 3 起跑時間 2021-04-14 14:53:31
run 8 起跑時間 2021-04-14 14:53:31
run 5 起跑時間 2021-04-14 14:53:31
run 7 起跑時間 2021-04-14 14:53:31
run 6 起跑時間 2021-04-14 14:53:31
run 2 預計到達終點時間 2021-04-14 14:53:33;完成比賽人數:1
run 6 預計到達終點時間 2021-04-14 14:53:34;完成比賽人數:2
run 4 預計到達終點時間 2021-04-14 14:53:34;完成比賽人數:3
run 8 預計到達終點時間 2021-04-14 14:53:35;完成比賽人數:4
run 3 預計到達終點時間 2021-04-14 14:53:38;完成比賽人數:5
run 1 預計到達終點時間 2021-04-14 14:53:39;完成比賽人數:6
run 7 預計到達終點時間 2021-04-14 14:53:39;完成比賽人數:7
run 5 預計到達終點時間 2021-04-14 14:53:40;完成比賽人數:8
全部完成 2021-04-14 14:53:40
全部完成 2021-04-14 14:53:40
全部完成 2021-04-14 14:53:40
全部完成 2021-04-14 14:53:40
全部完成 2021-04-14 14:53:40
全部完成 2021-04-14 14:53:40
全部完成 2021-04-14 14:53:40
全部完成 2021-04-14 14:53:40

Process finished with exit code 0


           

CyclicBarrier(int parties, Runnable barrierAction)

建立一個新的 CyclicBarrier ,當給定數量的線程(線程)等待時,它将跳閘,當屏障跳閘時執行給定的屏障動作,由最後一個進入屏障的線程執行。

package com.muyi;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;

/**
 * @Author: muyi
 * @Date: 2021/3/23 10:27
 */
public class Main {

    final static SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    public static void main(String[] args) throws InterruptedException
    {

        CyclicBarrier cyclicBarrier = new CyclicBarrier(8,new Runnable(){
            @Override
            public void run() {
                System.out.println("********裁判組記錄,發令***********");
                System.out.println(sdf.format(new Date()));
            }
        });
        Runner run1 = new Runner(1, cyclicBarrier);
        Runner run2 = new Runner(2, cyclicBarrier);
        Runner run3 = new Runner(3, cyclicBarrier);
        Runner run4 = new Runner(4, cyclicBarrier);
        Runner run5 = new Runner(5, cyclicBarrier);
        Runner run6 = new Runner(6, cyclicBarrier);
        Runner run7 = new Runner(7, cyclicBarrier);
        Runner run8 = new Runner(8, cyclicBarrier);

        run1.start();
        run2.start();
        run3.start();
        run4.start();
        run5.start();
        run6.start();
        run7.start();
        run8.start();
    }

    static class Runner extends Thread {
        int no;
        CyclicBarrier cyclicBarrier;
        public Runner(int no, CyclicBarrier cyclicBarrier) {
            this.no = no;
            this.cyclicBarrier=cyclicBarrier;
        }
        @Override
        public void run() {
            try {
                Random random = new Random(no);
                Integer runTime = random.nextInt(5000)*2;
                Thread.sleep(runTime/10);// 放大線程準備時間
                System.out.println("run "+no+"進入賽道,等待開始!預計用時:"+runTime+"ms,準備完成人數:"+(cyclicBarrier.getNumberWaiting()+1));
                cyclicBarrier.await();
                System.out.println("run " + no + " 起跑時間 "+ sdf.format(new Date()));
                Thread.sleep(runTime);
                System.out.println("run " + no + " 預計到達終點時間 " + sdf.format(new Date())+";完成比賽人數:"+(cyclicBarrier.getNumberWaiting()+1));
                cyclicBarrier.await();
                System.out.println("全部完成 " + sdf.format(new Date()));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}


//out
run 2進入賽道,等待開始!預計用時:2216ms,準備完成人數:1
run 6進入賽道,等待開始!預計用時:3222ms,準備完成人數:2
run 4進入賽道,等待開始!預計用時:3724ms,準備完成人數:3
run 8進入賽道,等待開始!預計用時:4728ms,準備完成人數:4
run 3進入賽道,等待開始!預計用時:7468ms,準備完成人數:5
run 1進入賽道,等待開始!預計用時:7970ms,準備完成人數:6
run 7進入賽道,等待開始!預計用時:8472ms,準備完成人數:7
run 5進入賽道,等待開始!預計用時:8974ms,準備完成人數:8
********裁判組記錄,發令***********
2021-04-14 14:55:54
run 5 起跑時間 2021-04-14 14:55:54
run 2 起跑時間 2021-04-14 14:55:54
run 4 起跑時間 2021-04-14 14:55:54
run 3 起跑時間 2021-04-14 14:55:54
run 7 起跑時間 2021-04-14 14:55:54
run 6 起跑時間 2021-04-14 14:55:54
run 1 起跑時間 2021-04-14 14:55:54
run 8 起跑時間 2021-04-14 14:55:54
run 2 預計到達終點時間 2021-04-14 14:55:56;完成比賽人數:1
run 6 預計到達終點時間 2021-04-14 14:55:57;完成比賽人數:2
run 4 預計到達終點時間 2021-04-14 14:55:58;完成比賽人數:3
run 8 預計到達終點時間 2021-04-14 14:55:59;完成比賽人數:4
run 3 預計到達終點時間 2021-04-14 14:56:02;完成比賽人數:5
run 1 預計到達終點時間 2021-04-14 14:56:02;完成比賽人數:6
run 7 預計到達終點時間 2021-04-14 14:56:03;完成比賽人數:7
run 5 預計到達終點時間 2021-04-14 14:56:03;完成比賽人數:8
********裁判組記錄,發令***********
2021-04-14 14:56:03
全部完成 2021-04-14 14:56:03
全部完成 2021-04-14 14:56:03
全部完成 2021-04-14 14:56:03
全部完成 2021-04-14 14:56:03
全部完成 2021-04-14 14:56:03
全部完成 2021-04-14 14:56:03
全部完成 2021-04-14 14:56:03
全部完成 2021-04-14 14:56:03