Existe alguma vantagem em usar
java.util.concurrent.CountdownLatch
ao invés de
java.util.concurrent.Semaphore ?
Pelo que eu posso dizer, os seguintes fragmentos são quase equivalentes:
1. Semáforo
final Semaphore sem = new Semaphore(0);
for (int i = 0; i < num_threads; ++ i)
{
Thread t = new Thread() {
public void run()
{
try
{
doStuff();
}
finally
{
sem.release();
}
}
};
t.start();
}
sem.acquire(num_threads);
2: CountDownLatch
final CountDownLatch latch = new CountDownLatch(num_threads);
for (int i = 0; i < num_threads; ++ i)
{
Thread t = new Thread() {
public void run()
{
try
{
doStuff();
}
finally
{
latch.countDown();
}
}
};
t.start();
}
latch.await();
Exceto que, no caso nº 2, a trava não pode ser reutilizada e, mais importante, você precisa saber com antecedência quantos threads serão criados (ou espere até que todos sejam iniciados antes de criar a trava).
Então, em que situação a trava pode ser preferível?
CountDownLatch é usado para iniciar uma série de threads e, em seguida, esperar até que todas sejam concluídas (ou até que chamem
countDown()
um determinado número de vezes.O semáforo é usado para controlar o número de threads simultâneos que estão usando um recurso. Esse recurso pode ser algo como um arquivo ou pode ser a cpu, limitando o número de threads em execução. A contagem em um semáforo pode aumentar e diminuir conforme diferentes threads chamam
acquire()
erelease()
.Em seu exemplo, você está essencialmente usando o Semaphore como uma espécie de Count UP Latch. Visto que sua intenção é aguardar o término de todos os fios, usar o
CountdownLatch
torna sua intenção mais clara.fonte
Pequeno resumo:
Semaphore e CountDownLatch têm uma finalidade diferente.
Use o Semaphore para controlar o acesso do thread ao recurso.
Use CountDownLatch para aguardar a conclusão de todos os threads
Definição de semáforo de javadocs:
No entanto, nenhum objeto de licença real é usado; o Semaphore apenas mantém uma contagem do número disponível e age de acordo.
Como funciona ?
Os semáforos são usados para controlar o número de threads simultâneos que estão usando um recurso. Esse recurso pode ser algo como dados compartilhados, ou um bloco de código ( seção crítica ) ou qualquer arquivo.
A contagem em um semáforo pode aumentar e diminuir conforme diferentes threads chamam
acquire
() erelease
(). Mas, em qualquer ponto do tempo, você não pode ter mais número de threads maior do que a contagem do Semaphore.Casos de uso de semáforo:
Dê uma olhada neste artigo para usos de semáforo.
Definição CountDownLatch de javadocs:
Como funciona?
CountDownLatch funciona tendo um contador inicializado com número de threads, que é diminuído cada vez que uma thread completa sua execução. Quando a contagem chega a zero, significa que todos os encadeamentos concluíram sua execução e o encadeamento em espera retoma a execução.
Casos de uso CountDownLatch:
Dê uma olhada neste artigo para entender os conceitos de CountDownLatch claramente.
Dê uma olhada em Fork Join Pool neste artigo também. Ele tem algumas semelhanças com CountDownLatch .
fonte
Digamos que você entrou na loja de golfe profissional, esperando encontrar um quarteto,
Quando você fica na fila para obter um tee time de um dos atendentes da loja de artigos esportivos, basicamente você liga
proshopVendorSemaphore.acquire()
, assim que consegue um tee time, vocêproshopVendorSemaphore.release()
liga. Nota: qualquer um dos atendentes gratuitos pode atender você, ou seja, um recurso compartilhado.Agora você anda até o starter, ele inicia um
CountDownLatch(4)
e chamaawait()
para esperar pelos outros, de sua parte você chamou check-in ieCountDownLatch
.countDown()
e o mesmo acontece com o resto do quarteto. Quando todos chegam, o iniciador dá prosseguimento (await()
devolução da chamada)Agora, depois de nove buracos, quando cada um de vocês faz uma pausa, hipoteticamente vamos envolver o iniciador novamente, ele usa um 'novo'
CountDownLatch(4)
para dar a tacada inicial no Buraco 10, a mesma espera / sincronização do Buraco 1.No entanto, se o starter usou um
CyclicBarrier
para começar, ele poderia ter reiniciado a mesma instância no Buraco 10 em vez de uma segunda trava, que usa e lança.fonte
Olhando para a fonte disponível gratuitamente, não há mágica na implementação das duas classes, portanto, seu desempenho deve ser o mesmo. Escolha aquele que torna sua intenção mais óbvia.
fonte
CountdownLatch
faz com que os threads esperem noawait()
método, até que a contagem chegue a zero. Então, talvez você queira que todos os seus threads esperem até 3 invocações de algo, então todos os threads podem ir. ALatch
geralmente não pode ser redefinida.Um
Semaphore
permite que os threads recuperem permissões, o que impede que muitos threads sejam executados de uma vez, bloqueando se não puder obter a (s) licença (s) necessária (s) para prosseguir. As permissões podem ser devolvidas a umSemaphore
permitindo que os outros threads em espera continuem.fonte