Puis-je obtenir un scénario simple c'est à dire tutoriel qui suggèrent que la façon dont cela devrait être utilisé, notamment avec une File d'attente?
Réponses
Trop de publicités?L' wait()
et notify()
méthodes sont conçues pour fournir un mécanisme pour permettre à un fil à bloc jusqu'à ce qu'une condition particulière est remplie. Pour cela, je suppose que vous êtes désireux d'écrire une file d'attente de blocage de la mise en œuvre, où vous avez quelques fixe la taille de la sauvegarde de stocker des éléments.
La première chose que vous avez à faire est d'identifier les conditions que vous souhaitez les méthodes d'attendre. Dans ce cas, vous voudrez l' put()
méthode pour bloquer jusqu'à ce qu'il y a de l'espace libre dans le magasin, et vous voulez l' take()
méthode pour bloquer jusqu'à ce que il ya certains éléments de retour.
public class BlockingQueue<T> {
private Queue<T> queue = new LinkedList<T>();
private int capacity;
public BlockingQueue(int capacity) {
this.capacity = capacity;
}
public synchronized void put(T element) throws InterruptedException {
while(queue.size() == capacity) {
wait();
}
queue.add(element);
notify();
}
public synchronized T take() throws InterruptedException {
while(queue.isEmpty()) {
wait();
}
T item = queue.remove();
notify();
return item;
}
}
Il y a quelques choses à noter à propos de la façon dont vous devez utiliser les attendre et de les informer des mécanismes.
Tout d'abord, vous devez vous assurer que tous les appels à des wait()
ou notify()
sont dans un synchronisé région de code (avec l' wait()
et notify()
des appels sont synchronisés sur le même objet). La raison de cette (autre que le thread des problèmes de sécurité) est due à quelque chose de connu comme un raté du signal.
Un exemple de cela, c'est qu'un thread peut appeler put()
lorsque la file d'attente qui se passe pour être complet, il vérifie ensuite l'état, voit que la file d'attente est pleine, cependant, avant de pouvoir bloquer un autre thread est prévue. Cette deuxième thread take()
's un élément de la file d'attente, et en informe les threads en attente que la file d'attente n'est plus complet. Parce que le premier thread a déjà vérifié la condition toutefois, il sera tout simplement appel wait()
, après avoir été prévue, même si elle pourrait faire des progrès.
Par la synchronisation sur un objet partagé, vous pouvez vous assurer que ce problème ne se produit pas, du deuxième thread take()
appel ne sera pas en mesure de faire des progrès jusqu'à ce que le premier thread a effectivement bloqué.
Deuxièmement, vous avez besoin de mettre la condition que vous vérifiez dans une boucle while, plutôt que d'une instruction si, en raison d'un problème connu comme la fausse wake-up. C'est là un thread en attente peut parfois être réactivé sans notify()
de la demande. Mettre cette case dans une boucle while permettra de s'assurer que si un faux réveil se produit, la condition sera vérifiée à nouveau, et le thread va appeler wait()
de nouveau.
Comme certains des autres réponses ont mentionné, Java 1.5 introduit une nouvelle simultanéité de la bibliothèque (en java.util.concurrent
package) qui a été conçu pour fournir un haut niveau d'abstraction au-dessus de l'wait/notify mécanisme. L'utilisation de ces nouvelles fonctionnalités, vous pouvez réécrire l'exemple d'origine comme suit:
public class BlockingQueue<T> {
private Queue<T> queue = new LinkedList<T>();
private int capacity;
private Lock lock = new ReentrantLock();
private Condition notFull = lock.newCondition();
private Condition notEmpty = lock.newCondition();
public BlockingQueue(int capacity) {
this.capacity = capacity;
}
public void put(T element) throws InterruptedException {
lock.lock();
try {
while(queue.size() == capacity) {
notFull.await();
}
queue.add(element);
notEmpty.signal();
} finally {
lock.unlock();
}
}
public T take() throws InterruptedException {
lock.lock();
try {
while(queue.isEmpty()) {
notEmpty.await();
}
T item = queue.remove();
notFull.signal();
return item;
} finally {
lock.unlock();
}
}
}
Bien sûr, si vous avez réellement besoin d'une file d'attente de blocage, alors vous devriez utiliser une mise en œuvre de la BlockingQueue interface.
Aussi, pour des choses comme cela, je recommande fortement d' Java de la Simultanéité dans la Pratique, car il couvre tout ce que vous voulez savoir sur la simultanéité liés à des problèmes et des solutions.
Pas une file d'attente, par exemple, mais extrêmement simple :)
class MyHouse {
private boolean pizzaArrived = false;
public void eatPizza(){
synchronized(this){
while(!pizzaArrived){
wait();
}
}
System.out.println("yumyum..");
}
public void pizzaGuy(){
synchronized(this){
this.pizzaArrived = true;
notifyAll();
}
}
}
Quelques points importants:
1) ne JAMAIS faire
if(!pizzaArrived){
wait();
}
Toujours utiliser while(condition), parce que
- a) threads peuvent sporadiquement éveillé à partir d'attente sans être notifié par n'importe qui. (même lors de la pizza guy n'a pas sonner le carillon, quelqu'un aurait décider essayez de manger le la pizza.).
- b) Vous devez vérifier la
condition encore après l'acquisition de la
synchronisé de verrouillage. Disons pizza
ne durent pas éternellement. Vous vous réveillez,
line-up pour la pizza, mais il n'est pas
assez pour tout le monde. Si vous n'avez pas
vérifier, vous pouvez manger du papier! :)
(probablement le meilleur exemple serait
while(!pizzaExists){ wait(); }
.
2) Vous devez être titulaire de la serrure (synchronisé) avant d'invoquer attendre/nofity. Les Threads doivent également acquérir verrouillage avant de se réveiller.
3) Essayez d'éviter l'acquisition d'un verrou dans votre bloc synchronisé et s'efforcer de ne pas invoquer l'étranger méthodes (méthodes vous ne savez pas ce qu'ils font). Si vous devez le faire, assurez-vous de prendre des mesures pour éviter les blocages.
4) soyez prudent avec notify(). Bâton avec notifyAll() jusqu'à ce que vous savez ce que vous faites.
5)en Dernier, mais pas moins, de lire Java de la Simultanéité dans la Pratique!
Même si vous avez demandé l' wait()
et notify()
plus précisément, je pense que cette citation est encore assez important:
Josh Bloch, Efficace Java 2nd Edition, Article 69: Préférez la simultanéité des utilitaires pour wait
et notify
(les italiques sont de lui):
Compte tenu de la difficulté de l'utilisation de
wait
etnotify
correctement, vous devez utiliser le niveau supérieur de la simultanéité des utilitaires au lieu [...] à l'aide d'wait
etnotify
directement, c'est comme la programmation de "la simultanéité de l'assemblée de la langue", par rapport au plus haut niveau de langage fournis parjava.util.concurrent
. Il est rarement, sinon jamais, en raison de l'utilisation d'wait
etnotify
dans le nouveau code.
Avez-vous pris un coup d'oeil à ce Tutoriel Java?
De plus, je vous conseille de rester le diable loin de jouer avec ce genre de trucs dans la vraie logiciel. Il est bon de jouer avec elle, de sorte que vous savez ce que c'est, mais la simultanéité a des pièges partout. Il est préférable d'utiliser des abstractions de plus haut niveau et la synchronisation des collections ou des files d'attente JMS si vous êtes à la création de logiciels pour d'autres personnes.
C'est au moins ce que je fais. Je ne suis pas une simultanéité expert donc je rester à l'écart de la manipulation de threads par la main dans la mesure du possible.