Dans votre code, alors que le fil est bloqué sur BlockingQueue.take()
, il s'accroche au verrouillage this
. Le verrou n'est libéré que lorsque le code quitte le bloc synchronisé ou que this.wait()
est appelé.
Ici, je suppose que moveToFirst()
et moveToSecond()
devraient bloquer, et que votre classe contrôle tous les accès aux files d'attente.
private final BlockingQueue<Object> firstQ = new LinkedBlockingQueue();
private final Semaphore firstSignal = new Semaphore(0);
private final BlockingQueue<Object> secondQ = LinkedBlockingQueue();
private final Semaphore secondSignal = new Semaphore(0);
private final Object monitor = new Object();
public void moveToSecond() {
int moved = 0;
while (moved == 0) {
// bock until someone adds to the queue
firstSignal.aquire();
// attempt to move an item from one queue to another atomically
synchronized (monitor) {
moved = firstQ.drainTo(secondQ, 1);
}
}
}
public void putInFirst(Object object) {
firstQ.put(object);
// notify any blocking threads that the queue has an item
firstSignal.release();
}
Vous auriez un code similaire pour moveToFirst()
et putInSecond()
. Le while
n'est nécessaire que si un autre code peut supprimer des éléments de la file d'attente. Si vous voulez que la méthode qui supprime dans la file d'attente pour attendre les mouvements en attente, il devrait acquérir un permis du sémaphore, et le sémaphore devrait être créé comme un bon sémaphore, donc le premier thread à appeler aquire
sera publié en premier:
firstSignal = new Semaphore(0, true);
Si vous ne voulez pas vous bloquer moveToFirst()
avez quelques options
- ont la méthode ne faire son travail dans un
Runnable
envoyé à un Executor
- Passer un délai d'attente pour
moveToFirst()
et utiliser BlockingQueue.poll(int, TimeUnit)
- Utilisez
BlockingQueue.drainTo(secondQ, 1)
et modifiez moveToFirst()
pour renvoyer un booléen pour indiquer s'il a réussi.
Pour les trois options ci-dessus, vous n'avez pas besoin du sémaphore.
Enfin, je doute de la nécessité de rendre le mouvement atomique. Si plusieurs threads ajoutent ou suppriment des files d'attente, une file d'attente d'observation ne serait pas capable de dire si moveToFirst()
était atomique.
Le verrouillage a été recommandé en Java 1.5 sur wait() pour des raisons d'efficacité. En Java 1.6, ils ont presque le même niveau d'efficacité. Les futures optimisations de VM rendront probablement les implémentations wait/notify plus rapides. –
Mais le verrouillage est beaucoup plus facile à utiliser correctement. – JesperE
Comment cela résout-il le problème de l'OP de la première file d'attente étant vide? Le code bloquera toujours indéfiniment sur la méthode take(). – Adamski