En attente de condition en Java
Je veux faire un thread qui met des valeurs à une file d'attente lorsqu'il se vide et attendre pour cette condition alors qu'il ne l'est pas. Voici le code que j'ai essayé de l'utiliser, mais il imprime
Adding new
Taking Value 1
Taking Value 2
Taking Value 3
Taking Value 4
De sorte qu'il fonctionne qu'une seule fois. Quel est le problème?
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class SO {
public String test;
public String[] list = new String[] {test};
public static void main(String[] args) {
new SO();
}
public SO() {
go();
}
BlockingQueue<String> qq = new LinkedBlockingQueue<String>();
class Producer implements Runnable {
public void run() {
try {
while (true) {
synchronized (this) {
while (qq.size() > 0)
wait();
System.out.println("Adding new");
qq.put("Value 1");
qq.put("Value 2");
qq.put("Value 3");
qq.put("Value 4");
}
}
} catch (InterruptedException ex) {}
}
}
class Consumer implements Runnable {
public void run() {
try {
while(true) {
System.out.println("Taking " + qq.take()+". "+String.valueOf(qq.size())+" left");
Thread.sleep(1000);
}
} catch (InterruptedException ex) {}
}
}
public void go() {
Producer p = new Producer();
Consumer c = new Consumer();
new Thread(p).start();
new Thread(c).start();
}
}
- Au lieu d'utiliser wait/notify et associées à la taille de la logique de la vérification, vous pouvez faire cela (en fonction de si oui ou non vous voulez toujours avoir plus d'un objet dans la file d'attente à la consommation) à l'aide de
LinkedBlockingQueue.put
sur une file d'attente de capacité 1. Leput
méthode javadocs dire: "Insère l'élément spécifié à la fin de cette file d'attente, en attendant, si nécessaire, de l'espace disponible."
Vous devez vous connecter pour publier un commentaire.
Le wait() continuera à jamais, parce que vous n'appelez jamais notify().
Vous pourriez attendre dans la file d'attente et l'appel en informer quand vous voulez le thread en attente de réveil. Pour ce faire vous devez changer de Producteur pour lire:
Et de changement des Consommateurs à lire:
Comme le dit Steve dans sa réponse, vous pourriez aussi utiliser wait() dans le thread consommateur de sorte qu'il peut attendre jusqu'à ce qu'il y a quelque chose dans la liste plutôt que de dormir. Ainsi, votre code devient:
wait()
n'est jamais avisé.Sice vous utilisez
BlockingQueue
, vous n'avez pas à utilisersynchronized
, parce queBlockingQueue
est sychronized par défaut. Si vous souhaitez utiliser la synchronisation, vous devez synchroniser auge le même objet:et de la consommation de la méthode doit être enveloppé dans
synchronized(theSameObjectInstance)
afin de recevoir la notification, les consommateurs devraient également "attendre" quelque part, par exemple, quand qq est vide.Vos exigences, que vous avez l'intention de mettre valeurs dans la file d'attente lorsqu'il est vide -- plusieurs valeurs, je le prends, plutôt qu'une seule. Si vos besoins changent légèrement de dire que vous mettez un élément dans la file d'attente et attendre jusqu'à ce qu'il est consommé avant de mettre un autre, alors vous seriez venu d'utiliser
java.util.de façon concomitante.Échangeur
.Son comportement est semblable à un
BlockingQueue
de profondeur, mais il fait un peu plus: Il passe d'un objet à la fois des moyens, où chaque participant est à la fois un "producteur" et "consommateur". Par conséquent, unExchanger
de ne pas accepter un "producteur"de l'offre d'un élément jusqu'à ce que le "consommateur" est également prêt à offrir un point de revenir. Ce n'est pas "fire and forget" pour le "producteur"; de la production et de la consommation, le timing est interloqué. Cela empêche un véritable producteur de l'inondation d'un consommateur de file d'attente de travail, encore une fois, commeBlockingQueue
-- mais aussi des étals de la production jusqu'à la consommation a terminé le dernier cycle de travail.Dans votre cas, le consommateur ne pourrait pas avoir quelque chose d'utile pour revenir au producteur. Peu importe, vous pouvez composer un protocole entre les participants. Lorsque le producteur veut le thread consommateur à l'arrêt, il peut offrir une valeur null. Une fois que le consommateur accepte la valeur null, le producteur peut faire un tour de plus d'échange afin de finaliser la demande d'arrêt et de recueillir tout résultat final du consommateur.