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).

Author: skeggse, 2011-08-19

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 notify pour une description des façons dont un thread peut devenir propriétaire d'un moniteur.

Jeter:

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.
 54
Author: dlev, 2014-02-25 20:56:18

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.

 6
Author: Jon Skeet, 2011-08-19 19:40:19