Como faço para obter o java.concurrency.cyclicBarrier para funcionar conforme o esperado
-
22-09-2019 - |
Pergunta
Estou escrevendo código que gerará dois threads e, em seguida, esperará que eles sincronizem usando a classe CyclicBarrier. O problema é que a barreira cíclica não está funcionando como o esperado e o encadeamento principal não espera que os threads individuais terminem. Veja como meu código parece:
class mythread extends Thread{
CyclicBarrier barrier;
public mythread(CyclicBarrier barrier) {
this.barrier = barrier;
}
public void run(){
barrier.await();
}
}
class MainClass{
public void spawnAndWait(){
CyclicBarrier barrier = new CyclicBarrier(2);
mythread thread1 = new mythread(barrier).start();
mythread thread2 = new mythread(barrier).start();
System.out.println("Should wait till both threads finish executing before printing this");
}
}
Alguma ideia do que estou fazendo de errado? Ou existe uma maneira melhor de escrever esses métodos de sincronização de barreira? Por favor ajude.
Solução
Durante a execução do seu tópico principal, você cria outros dois threads e diz para eles esperarem um pelo outro. Mas você não escreveu nada para fazer seu tópico principal para esperar por eles e reclamar que não espera. Tentar
CyclicBarrier barrier = new CyclicBarrier(3);
mythread thread1 = new mythread(barrier).start();
mythread thread2 = new mythread(barrier).start();
barrier.await(); // now you wait for two new threads to reach the barrier.
System.out.println("Should wait till both threads finish executing before printing this");
POR FALAR NISSO. Não estenda a classe de threads, a menos que você precise. Implemente o Runnable e passe implementações para os objetos Thread. Assim:
class MyRunnable implements Runnable {
public void run(){
// code to be done in thread
}
}
Thread thread1 = new Thread(MyRunnable);
thread1.start();
EDITAR
Justificativa para evitar a extensão do encadeamento.
A regra geral é o mínimo possível de acoplamento. A herança é uma conexão muito forte entre as classes. Você precisa herdar do thread se deseja alterar parte de seu comportamento padrão (ou seja, substituir alguns métodos) ou querer acessar alguns campos protegidos do thread de classe. Se você não quiser, escolhe o acoplamento mais frouxo - implementando o Runnable e passando -o como um parâmetro construtor para a instância do encadeamento.
Outras dicas
Passe a Runnable
instância para o construtor do seu CyclicBarrier
assim.
CyclicBarrier barrier = new CyclicBarrier(2, new Runnable() {
@Override
public void run() {
System.out.println("Should wait till both threads finish executing before printing this");
}
});
new mythread(barrier).start();
new mythread(barrier).start();
Você está procurando Thread.Join () método...
thread1.join();
thread2.join();
System.out.println("Finished");
EDITAR: por causa dos comentários ...
E se você não quiser esperar para sempre, também pode especificar o número máximo de milissegundos mais nanossegundos para esperar que o tópico morra
A barreira cíclica não é a escolha correta neste caso. Você deve usar CountDownLatch
aqui.
Eu suponho que você tem está invocando spawnAndWait
Método do método principal.
A razão pela qual isso não funciona é que o CyclicBarrier
tem 2 construtores. Para executar pós-operações, você deve usar um construtor de 2 parâmetros. A coisa mais importante a lembrar é que o tópico principal não vai esperar pelo await
método; mas continuará a executar. No entanto, o tópico especificado no CyclicBarrier
o construtor só funcionará quando todos os fios gerados pararem na barreira (pelo await
método)