Jak CountDownLatch jest używany w wielowątkowości Java?

183

Czy ktoś może mi pomóc zrozumieć, czym CountDownLatchjest Java i kiedy z niej korzystać?

Nie mam bardzo jasnego pojęcia o tym, jak działa ten program. Jak rozumiem, wszystkie trzy wątki zaczynają się od razu i każdy wątek wywoła CountDownLatch po 3000ms. Więc odliczanie zmniejszy się jeden po drugim. Gdy zatrzask zmieni się na zero, program wyświetli komunikat „Zakończono”. Może sposób, w jaki zrozumiałem, jest nieprawidłowy.

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

class Processor implements Runnable {
    private CountDownLatch latch;

    public Processor(CountDownLatch latch) {
        this.latch = latch;
    }

    public void run() {
        System.out.println("Started.");

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        latch.countDown();
    }
}

// ------------------------------------------------ -----

public class App {

    public static void main(String[] args) {

        CountDownLatch latch = new CountDownLatch(3); // coundown from 3 to 0

        ExecutorService executor = Executors.newFixedThreadPool(3); // 3 Threads in pool

        for(int i=0; i < 3; i++) {
            executor.submit(new Processor(latch)); // ref to latch. each time call new Processes latch will count down by 1
        }

        try {
            latch.await();  // wait until latch counted down to 0
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Completed.");
    }

}
amal
źródło
8
Właśnie użyłem twojego przykładowego kodu pytania dla partii usług równoległych Androida i działało to jak urok. Dziękuję bardzo!
Roisgoen,
Dostałem się tutaj z tego filmu z 2012 roku, który pokazuje niezwykłe podobieństwo do pokazanego tutaj przykładu. Dla wszystkich zainteresowanych jest to część serii wielowątkowych samouczków Java autorstwa faceta o imieniu John. Lubię Johna. Wysoce rekomendowane.
Elia Grady

Odpowiedzi:

194

Tak, zrozumiałeś poprawnie. CountDownLatchdziała na zasadzie zatrzasku, główny wątek będzie czekał na otwarcie bramy. Jeden wątek czeka na n wątków określonych podczas tworzenia CountDownLatch.

Każdy wątek, zwykle główny wątek aplikacji, którego wywołania CountDownLatch.await()będą czekać, aż liczba osiągnie zero lub zostanie przerwany przez inny wątek. Wszystkie pozostałe wątki muszą odliczać, dzwoniąc CountDownLatch.countDown()po ich ukończeniu lub gotowości.

Gdy tylko liczba osiągnie zero, wątek oczekujący jest kontynuowany. Jedną z wad / zalet tego CountDownLatchjest to, że nie można go ponownie użyć: gdy liczba osiągnie zero, nie można już z niego korzystać CountDownLatch.

Edytować:

Użyj, CountDownLatchgdy jeden wątek (jak główny wątek) wymaga oczekiwania na ukończenie jednego lub więcej wątków, zanim będzie mógł kontynuować przetwarzanie.

Klasycznym przykładem użycia CountDownLatchw Javie jest aplikacja Java po stronie serwera, która korzysta z architektury usług, w której wiele usług jest udostępnianych przez wiele wątków, a aplikacja nie może rozpocząć przetwarzania, dopóki wszystkie usługi nie zostaną pomyślnie uruchomione.

Pytanie PS OP ma całkiem prosty przykład, więc go nie uwzględniłem.

NikolaB
źródło
1
Dziękuję za odpowiedź. Czy możesz podać przykład zastosowania zatrzasku CountDown?
amal
11
samouczek korzystania z CountDownLatch znajduje się tutaj howtodoinjava.com/2013/07/18/…
thiagoh
1
@NikolaB Ale w tym przykładzie możemy osiągnąć ten sam wynik za pomocą metody łączenia, prawda?
Vikas Verma
3
Uważam, że jednorazowość jest zaletą: jesteś pewien, że nikt nie może go zresetować ani zwiększyć liczby.
ataulm
3
Ładne wyjaśnienie. Ale nieco nie zgodziłbym się co do tego One thread waits for n number of threads specified while creating CountDownLatch in Java. Jeśli potrzebujesz takiego mechanizmu, rozważne jest jego użycie CyclicBarrier. Fundamentalna różnica koncepcyjna pomiędzy tymi dwoma, jak podano w Java concurrency in Practiceto: Latches are for waiting for events; barriers are for waiting for other threads. cyclicBarrier.await()przechodzi w stan blokowania.
Rahul Dev Mishra