Comment puis-je obtenir le java.concurrency.CyclicBarrier de travailler comme prévu
-
22-09-2019 - |
Question
Je suis en train d'écrire un code qui engendrera deux fils, puis attendre pour eux de se synchroniser à l'aide de la classe CyclicBarrier. Le problème est que la barrière cyclique ne fonctionne pas comme prévu et le principal ne marche pas de fil d'attente pour les fils individuels pour terminer. Voici comment mon code ressemble:
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");
}
}
Toute idée de ce que je fais mal? Ou est-il une meilleure façon d'écrire ces méthodes de synchronisation de barrière? S'il vous plaît aider.
La solution
Lors de l'exécution de votre thread principal vous créez deux autres fils et leur dire d'attendre les uns des autres. Mais vous avez écrit rien à faire de votre fil conducteur d'attendre pour eux et se plaindre n'attend pas. Essayez
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");
BTW. Ne pas étendre la classe de fil à moins que vous devez. Mettre en œuvre Runnable et passer à la discussion des implémentations des objets. Comme ceci:
class MyRunnable implements Runnable {
public void run(){
// code to be done in thread
}
}
Thread thread1 = new Thread(MyRunnable);
thread1.start();
EDIT
Justification pour éviter étendre cette discussion.
La règle de base est aussi peu que possible le couplage. L'héritage est un lien très fort entre les classes. Vous devez hériter de fil si vous voulez changer une partie de son comportement par défaut (à savoir remplacer certaines méthodes) ou si vous voulez accéder à certains champs protégés de fil de classe. Si vous ne voulez pas, vous choisissez un couplage plus lâche -. Et la mise en œuvre Runnable passant comme paramètre constructeur à Enfiler exemple
Autres conseils
Passez une instance de Runnable
au constructeur de votre CyclicBarrier
comme celui-ci.
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();
Vous cherchez Thread.join () méthode ...
thread1.join();
thread2.join();
System.out.println("Finished");
EDIT: en raison des commentaires ...
Et si vous ne voulez pas attendre pour toujours, vous pouvez également spécifier le nombre maximum de millisecondes, plus nanosecondes attendre le fil à mourir
Barrière cyclique n'est pas le bon choix dans ce cas. Vous devez utiliser CountDownLatch
ici.
Je suppose que vous avez invoquez méthode spawnAndWait
de la méthode principale.
La raison pour laquelle ce travail est que la coutume CyclicBarrier
a 2 constructeurs. Pour effectuer, vous devez utiliser un constructeur de 2 paramètres post-opérations. La chose la plus importante à retenir est que le thread principal ne sera pas attendre par la méthode await
; mais continuera à exécuter. Cependant, le fil spécifié dans le constructeur de CyclicBarrier
ne fonctionne que lorsque toutes les discussions engendrées arrêtent à la barrière (par la méthode de await
)