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 de code suivante .
Main.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();
}
}
Runner.Java:
class Runner implements Runnable
{
public void run()
{
try
{
Main.main.wait();
} catch (InterruptedException e) {}
System.out.println("Runner away!");
}
}
Actuellement, j'obtiens 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 qu'il ne notifierait qu'un seul thread, lorsque l'idée est de les notifier tous.
J'ai regardé Java.util.concurrent
, Mais je ne trouve pas de remplacement approprié (peut-être que je manque juste quelque chose).
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 synchronize
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 également à notify()
/notifyAll()
.
Les Javadocs pour wait()
mentionnent ceci:
Cette méthode ne doit être appelée que par un thread propriétaire du moniteur de cet objet. Voir la méthode
Lance: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 du moniteur de cet objet.
Et de notify()
:
Un thread devient le propriétaire du moniteur de l'objet de trois manières:
- 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 cette classe.
Vous appelez à la fois wait
et notifyAll
sans utiliser de bloc synchronized
. Dans les deux cas, le thread appelant doit possède le verrou sur le moniteur sur lequel vous appelez la méthode.
À partir des documents pour notify
(wait
et notifyAll
ont une documentation similaire mais référez-vous à 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 trois manières:
- 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 type Class, 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 exitwait
à la fois après notifyAll
car ils devront tous acquérir à nouveau le même moniteur - mais tout aura été averti, dès que le premier quitte le bloc synchronisé, le suivant acquiert le verrou, etc.