Est-il acceptable d'appeler notify() sur un objet lock avant d'appeler wait()?
Eh bien, cela dépend du contexte. À première vue, cela ne fait aucun mal.
Toutefois, si vous codez dépend du thread qui appelle wait()
voyant la notification spécifique, il ne fonctionnera pas. Les notifications ne sont pas mises en file d'attente. S'il n'y avait rien d'attente lorsque l'appel notify()
se produit, la notification est ignorée.
Cependant, votre code est cassé pour d'autres raisons.
Java wait/notify peut produire de fausses notifications; c'est à dire.un fil dans wait()
peut être réveillé sans un notify()
ou notifyAll()
spécifique. Votre code suppose que loadComplete
a été défini à la suite du retour du wait()
dans le thread A. Il ne peut pas supposer que ... à cause de wakeups parasites.
Vous supposez qu'un seul thread peut attendre la fin de la charge. Si ce n'est pas vrai, alors un thread sera réveillé, et le reste pourrait être bloqué pour toujours. Enfin, attraper et jeter Exception
comme cela est faux sur deux points.
- Vous interceptez/annulez toute autre exception cochée ou non cochée (à l'exception de
Error
, etc.).
- Vous ignorez l'exception vérifiée que vous doit être traitant. Si le thread A ou le thread B reçoit une interruption à un moment malencontreux, alors les choses vont se casser. En particulier le thread A pourrait penser que le code a chargé quand il n'a pas. Si vous n'avez pas l'intention de traiter les interruptions, alors les traiter comme un cas «cela ne devrait jamais arriver» ... et lancer un
AssertionError
, ou quelque chose d'équivalent.
Je vous conseille d'utiliser le modèle standard pour la mise en œuvre d'une variable de condition qui est présentée dans les java.lang.Object
javadocs. Utilisez une boucle, et n'essayez pas d'optimiser le cas de notifications inutiles. Et si vous ressentez le besoin d'optimiser, essayez d'utiliser l'une des constructions d'accès concurrentes de niveau supérieur (par exemple un «verrou») de préférence à l'implémentation de votre propre solution. Si vous êtes «créatif», vous pouvez avoir des ennuis. Et même si votre code est parfait, vous ferez du travail supplémentaire pour les gars qui conservent votre code. S'ils se heurtent à de mystérieux bogues concurrentiels, ils devront peut-être (ré) analyser votre solution «créative» à partir des premiers principes pour déterminer si elle est réellement saine.
Voici comment devrait implémenter ceci. Comme vous pouvez le voir, il y a moins de code que votre solution, et il est plus facile à comprendre:
ThreadA:
synchronized (syncObject) {
try {
// The loop deals with spurious wakeups.
while (!syncObject.isLoadComplete) {
syncObject.wait();
}
} catch (InterruptedException ex) {
// This is the "easy" way to do it correctly, in the case
// where interrupts are not designed for.
throw AssertionError("interrupted unexpectedly");
}
}
ThreadB:
synchronized (syncObject) {
if (!syncObject.isLoadComplete) {
syncObject.isLoadComplete = true;
syncObject.notifyAll(); // use `notify()` only if threadA
// is guaranteed to be the only waiter.
}
}
Si un arbre tombe dans une forêt, mais personne n'est là pour l'entendre, est-il un son? – erickson
C'est ce que je pensais aussi. Je voulais confirmer et je ne voulais pas prendre. – arun8