天天看點

CountDownLatch的簡單使用——Java并發程式設計Java并發程式設計

Java并發程式設計

CountDownLatch的使用

允許一個或多個線程等待直到在其他線程中執行的一組操作完成的同步輔助。

簡述

CountDownLatch

用給定的計數初始化。

await

方法阻塞,直到由于

countDown()

方法的調用而導緻目前計數達到零,之後所有等待線程被釋放,并且任何後續的

await

調用立即傳回。 這是一個一次性的現象 - 計數無法重置。 如果需要重置計數的版本,請考慮使用

CyclicBarrier

CountDownLatch

是一種通用的同步工具,可用于多種用途。 一個

CountDownLatch

為一個計數的CountDownLatch用作一個簡單的開/關鎖存器,或者門:所有線程調用

await

在門口等待,直到被調用

countDown()

的線程打開。 一個

CountDownLatch

初始化N可以用來做一個線程等待,直到N個線程完成某項操作,或某些動作已經完成N次。

CountDownLatch

一個有用的屬性是,它不要求調用

countDown

線程等待計數到達零之前繼續,它隻是阻止任何線程通過

await

,直到所有線程可以通過。

也就是相當于一個高鐵檢票口,需要在時間倒數到檢票時間的時候,才會放行,不然,都得在候車廳等待。此時高鐵就如同需要執行的下一個任務,乘客就相當于阻塞的線程。

API

其實對于這個類而言,涉及到的方法不多,隻有下面的幾個,是以運用也不是很難。

Modifier and Type Method and Description

void

await()

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

boolean

await(long timeout, TimeUnit unit)

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

void

countDown()

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

long

getCount()

傳回目前計數。

String

toString()

傳回一個辨別此鎖存器的字元串及其狀态。

示例程式

package CountDownLatchLearn;

import java.util.concurrent.CountDownLatch;

public class Latch {

    static class MyService {
        private CountDownLatch latch = new CountDownLatch(3);

        public void testMethod() {
            try {
                if (Thread.currentThread().getName().equals("線程4")) {
                    Thread.sleep(3000);
                }
                System.out.println(Thread.currentThread().getName() + "準備");
                latch.await();
                System.out.println(Thread.currentThread().getName() + "結束");
            } catch (InterruptedException e) {
                System.out.println("Exception:" + e);
                e.printStackTrace();
            }
        }

        public void downMethod() {
            latch.countDown();
        }
    }

    static class MyThread extends Thread {
        private MyService myService;

        public MyThread(MyService myService) {
            super();
            this.myService = myService;
        }

        @Override
        public void run() {
            myService.testMethod();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyService service = new MyService();
        MyThread[] threads = new MyThread[10];
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new MyThread(service);
            threads[i].setName("線程" + (i + 1));
            threads[i].start();
        }
        System.out.println("預備");
        for (int i = 3; i >= 1; i--) {
            System.out.println(i);
            Thread.sleep(1000);
            service.downMethod();
        }
        System.out.println("====START====");
    }

}

           

在這個簡單的程式中,設計的是一個起跑發令,主線程main用于放行所有準備好的線程,其中我專門設計一個線程的準備時間超過了main的最長等待時間,我們可以通過運作結果看出一點問題:

預備
3
線程3準備
線程10準備
線程1準備
線程9準備
線程2準備
線程6準備
線程7準備
線程8準備
線程5準備
2
1
====START====
線程10結束
線程6結束
線程1結束
線程9結束
線程3結束
線程7結束
線程4準備 =====> 别人都起跑了,才準備好
線程2結束
線程5結束
線程8結束
線程4結束

Process finished with exit code 0