Java Attendre et notifier: IllegalMonitorStateException
Je ne comprends pas complètement comment wait
et notify
(de Object
) fonctionnent, et par conséquent je suis obligé de réduire mes tentatives dans la section suivante du code.
Principal.java:
import java.util.ArrayList;
class Main
{
public static Main main = null;
public static int numRunners = 4;
public static ArrayList<Runner> runners = null;
public static void main(String[] args)
{
main = new Main();
}
Main()
{
runners = new ArrayList<Runner>(numRunners);
for (int i = 0; i < numRunners; i++)
{
Runner r = new Runner();
runners.add(r);
new Thread(r).start();
}
System.out.println("Runners ready.");
notifyAll();
}
}
Coureur.java:
class Runner implements Runnable
{
public void run()
{
try
{
Main.main.wait();
} catch (InterruptedException e) {}
System.out.println("Runner away!");
}
}
Actuellement, je reçois une exception IllegalMonitorStateException lors de l'appel de Main.main.wait();
, mais je ne comprends pas pourquoi. D'après ce que je peux voir, j'ai besoin de synchroniser Runner.run
, mais ce faisant, je suppose que cela ne notifierait qu'un seul thread, lorsque l'idée est de tous les notifier.
J'ai regardé java.util.concurrent
, mais je ne trouve pas de remplacement approprié (peut-être que je manque juste quelque chose).
2 answers
Vous ne pouvez pas wait()
sur un objet à moins que le thread actuel ne possède le moniteur de cet objet. Pour ce faire, vous devez {[2] } dessus:
class Runner implements Runnable
{
public void run()
{
try
{
synchronized(Main.main) {
Main.main.wait();
}
} catch (InterruptedException e) {}
System.out.println("Runner away!");
}
}
La même règle s'applique à notify()
/notifyAll()
ainsi.
Le Javadoc wait()
mentionner ceci:
Cette méthode ne doit être appelée que par un thread propriétaire du moniteur de cet objet. Voir la méthode
Jeter:notify
pour une description des façons dont un thread peut devenir propriétaire d'un moniteur.
IllegalMonitorStateException
– si le thread actuel n'est pas le propriétaire de cet objet du moniteur.
Et de notify()
:
Un thread devient le propriétaire du moniteur de l'objet dans l'un des trois façons:
- En exécutant une méthode d'instance synchronisée de cet objet.
- En exécutant le corps d'une instruction
synchronized
qui se synchronise sur l'objet.- Pour les objets de type
Class
, en exécutant une méthode statique synchronisée de que classe.
Vous appelez à la fois wait
et notifyAll
sans utiliser un bloc synchronized
. Dans les deux cas, le thread appelant doit posséder le verrou sur le moniteur sur lequel vous appelez la méthode.
Des documents pour notify
(wait
et notifyAll
ont une documentation similaire mais se référer à notify
pour la description la plus complète):
Cette méthode ne doit être appelée que par un thread propriétaire du moniteur de cet objet. Un thread devient le propriétaire du moniteur de l'objet de l'une des trois manières suivantes:
- En exécutant une méthode d'instance synchronisée de cet objet.
- En exécutant le corps d'une instruction synchronisée qui se synchronise sur l'objet.
- Pour les objets de classe type, en exécutant une méthode statique synchronisée de cette classe.
Un seul thread à la fois peut posséder le moniteur d'un objet.
Un seul thread pourra réellement quitter wait
à un moment après notifyAll
car ils devront tous acquérir le même moniteur encore une fois-mais tout aura été notifié, donc dès que le premier quittera le bloc synchronisé, le suivant acquerra le verrou, etc.