Alguém pode me ajudar a entender o que Java CountDownLatch
é e quando usá-lo?
Não tenho uma ideia muito clara de como esse programa funciona. Pelo que entendi, todos os três threads iniciam ao mesmo tempo e cada Thread chama o CountDownLatch após 3000ms. Portanto, a contagem decrescente diminuirá uma a uma. Depois que a trava se torna zero, o programa imprime "Concluído". Talvez a maneira como entendi esteja incorreta.
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.");
}
}
Respostas:
Sim, você entendeu corretamente.
CountDownLatch
funciona no princípio da trava, a rosca principal espera até que o portão seja aberto. Um segmento aguarda n encadeamentos, especificados ao criar oCountDownLatch
.Qualquer thread, geralmente o thread principal do aplicativo, que chama
CountDownLatch.await()
aguardarão até que a contagem chegue a zero ou seja interrompida por outro encadeamento. Todos os outros threads precisam fazer uma contagem regressiva chamandoCountDownLatch.countDown()
assim que estiverem concluídos ou prontos.Assim que a contagem chegar a zero, o encadeamento em espera continuará. Uma das desvantagens / vantagens de
CountDownLatch
não ser reutilizável: quando a contagem chega a zero, você não pode usarCountDownLatch
.Editar:
Use
CountDownLatch
quando um thread (como o thread principal) precisar aguardar a conclusão de um ou mais threads, antes de continuar o processamento.Um exemplo clássico de uso
CountDownLatch
em Java é um aplicativo Java principal do lado do servidor que usa arquitetura de serviços, em que vários serviços são fornecidos por vários encadeamentos e o aplicativo não pode iniciar o processamento até que todos os serviços tenham sido iniciados com êxito.A pergunta da PS OP tem um exemplo bastante direto, então não incluí um.
fonte
One thread waits for n number of threads specified while creating CountDownLatch in Java
. Se você precisar desse mecanismo, é prudente usarCyclicBarrier
. A diferença conceitual fundamental entre estes dois, tal como constaJava concurrency in Practice
é:Latches are for waiting for events; barriers are for waiting for other threads
.cyclicBarrier.await()
entra em um estado de bloqueio.CountDownLatch
in Java é um tipo de sincronizador que permiteThread
aguardar um ou maisThread
s antes de iniciar o processamento.CountDownLatch
funciona de acordo com o princípio da trava, a linha aguardará até que o portão seja aberto. Um thread aguarda on
número de threads especificado ao criarCountDownLatch
.por exemplo
final CountDownLatch latch = new CountDownLatch(3);
Aqui, ajustamos o contador para 3.
Qualquer encadeamento, geralmente o encadeamento principal do aplicativo, que as chamadas
CountDownLatch.await()
aguardarão até que a contagem chegue a zero ou seja interrompida por outraThread
. Todos os outros encadeamentos devem fazer a contagem regressiva chamandoCountDownLatch.countDown()
assim que estiverem concluídos ou prontos para o trabalho. assim que a contagem chegar a zero, aThread
espera começa a correr.Aqui a contagem é decrementada pelo
CountDownLatch.countDown()
métodoO
Thread
que chama oawait()
método aguardará até que a contagem inicial chegue a zero.Para fazer a contagem zero, outros threads precisam chamar o
countDown()
método Quando a contagem se tornar zero, o encadeamento que invocou oawait()
método será retomado (inicie sua execução).A desvantagem
CountDownLatch
é que não é reutilizável: uma vez que a contagem se torna zero, não é mais utilizável.fonte
new CountDownLatch(3)
como temos 3 threads donewFixedThreadPool
definido?NikolaB explicou muito bem, no entanto, o exemplo seria útil para entender, então aqui está um exemplo simples ...
fonte
É usado quando queremos esperar mais de um thread para concluir sua tarefa. É semelhante à junção de threads.
Onde podemos usar CountDownLatch
Considere um cenário em que temos requisitos em que temos três segmentos "A", "B" e "C" e queremos iniciar o segmento "C" somente quando os segmentos "A" e "B" concluírem ou concluírem parcialmente sua tarefa.
Pode ser aplicado ao cenário de TI do mundo real
Considere um cenário em que o gerente dividiu os módulos entre as equipes de desenvolvimento (A e B) e ele deseja atribuí-lo à equipe de controle de qualidade para teste apenas quando as duas equipes concluírem sua tarefa.
A saída do código acima será:
Tarefa atribuída à equipe de desenvolvimento devB
Tarefa atribuída à equipe de desenvolvimento devA
Tarefa concluída pela equipe de desenvolvimento devB
Tarefa concluída pela equipe de desenvolvimento devA
Tarefa atribuída à equipe de controle de qualidade
Tarefa concluída pela equipe de controle de qualidade
Aqui, o método waitit () aguarda que o sinalizador countdownlatch se torne 0 e o método countDown () diminui o sinalizador countdownlatch em 1.
Limitação de JOIN: O exemplo acima também pode ser alcançado com JOIN, mas JOIN não pode ser usado em dois cenários:
fonte
CoundDownLatch permite que você faça um thread aguardar até que todos os outros threads sejam concluídos com sua execução.
O pseudo-código pode ser:
fonte
Um bom exemplo de quando usar algo assim é com o Java Simple Serial Connector, acessando portas seriais. Normalmente, você escreve algo na porta e, de forma assíncrona, em outro encadeamento, o dispositivo responde em um SerialPortEventListener. Normalmente, você deseja fazer uma pausa depois de gravar na porta para aguardar a resposta. O manuseio manual dos bloqueios de encadeamento para esse cenário é extremamente complicado, mas o uso do Countdownlatch é fácil. Antes de pensar que pode fazê-lo de outra maneira, tenha cuidado com as condições de corrida em que nunca pensou!
Pseudo-código:
fonte
Se você adicionar alguma depuração após sua chamada para latch.countDown (), isso poderá ajudá-lo a entender melhor seu comportamento.
A saída mostrará o Count sendo decrementado. Essa 'contagem' é efetivamente o número de tarefas executáveis (objetos do processador) que você iniciou contra as quais countDown () não foi invocado e, portanto, está bloqueado no thread principal em sua chamada para latch.await ().
fonte
Da documentação da Oracle sobre CountDownLatch :
A
CountDownLatch
é inicializado com uma determinada contagem. Osawait
métodos bloqueiam até que a contagem atual atinja zero devido a invocações docountDown()
método, após o qual todos os threads em espera são liberados e quaisquer invocações subseqüentes de aguardam retornam imediatamente. Este é um fenômeno de uma vez - a contagem não pode ser redefinida.Uma
CountDownLatch
inicializada com uma contagem de um serve como uma trava simples de ligar / desligar, ou gate: todos os threads que chamam aguardam espera no gate até serem abertos por um thread que chama countDown ().Uma
CountDownLatch
inicializada para N pode ser usada para fazer um thread aguardar até que N threads concluam alguma ação ou que alguma ação tenha sido concluída N vezes.Se a contagem atual for zero, esse método retornará imediatamente.
Se a contagem atual for maior que zero, ela será decrementada. Se a nova contagem for zero, todos os threads em espera serão reativados para fins de planejamento de threads.
Explicação do seu exemplo.
Você definiu count como 3 para a
latch
variávelVocê passou isso compartilhado
latch
para o segmento Worker:Processor
Runnable
instâncias deProcessor
foram enviadas paraExecutorService
executor
O thread principal (
App
) está aguardando a contagem se tornar zero com a instrução abaixoProcessor
A linha dorme por 3 segundos e depois diminui o valor da contagem comlatch.countDown()
A primeira
Process
instância alterará a contagem de trava como 2 após sua conclusão devido alatch.countDown()
.A segunda
Process
instância mudará a contagem de trava como 1 após a conclusão devido alatch.countDown()
.A terceira
Process
instância alterará a contagem de trava como 0 após sua conclusão devido alatch.countDown()
.A contagem zero na trava faz com que a linha principal
App
saiaawait
O programa App imprime esta saída agora:
Completed
fonte
Este exemplo do Java Doc me ajudou a entender claramente os conceitos:
Interpretação visual:
Evidentemente,
CountDownLatch
permite que um thread (aquiDriver
) aguarde até que vários threads em execução (aquiWorker
) sejam concluídos com sua execução.fonte
Conforme mencionado em JavaDoc ( https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html ), CountDownLatch é um auxílio de sincronização, introduzido no Java 5. Aqui a sincronização não é significa restringir o acesso a uma seção crítica. Mas, em vez disso, sequenciar ações de diferentes threads. O tipo de sincronização alcançado através do CountDownLatch é semelhante ao do Join. Suponha que exista um encadeamento "M" que precise aguardar que outros encadeamentos de trabalho "T1", "T2", "T3" concluam suas tarefas. Antes do Java 1.5, da maneira que isso pode ser feito, M executando o código a seguir
O código acima garante que o thread M continue seu trabalho após T1, T2, T3 concluir seu trabalho. T1, T2, T3 podem concluir seu trabalho em qualquer ordem. O mesmo pode ser alcançado através do CountDownLatch, em que T1, T2, T3 e thread M compartilham o mesmo objeto CountDownLatch.
Solicitações "M":
countDownLatch.await();
onde "T1", "T2", "T3" não
countDownLatch.countdown();
Uma desvantagem do método de junção é que M precisa saber sobre T1, T2, T3. Se houver um novo thread de trabalho T4 adicionado posteriormente, M também precisará estar ciente disso. Isso pode ser evitado com CountDownLatch. Após a implementação, a sequência de ação seria [T1, T2, T3] (a ordem de T1, T2, T3 poderia ser de qualquer maneira) -> [M]
fonte
Melhor exemplo em tempo real para countDownLatch explicado neste link CountDownLatchExample
fonte
fonte