Newsgroup: it.comp.java
Titolo: Chiarimenti su wait() e notify()

Salve a tutti. Ho scritto questo breve classetta tanto per capire un
poco meglio come funzionano wait() e notify(), ve la riporto tanto per
capire:
public class NoPriorityMonitorKart
{
   //private boolean free;
 
   public class MutexVar
   {
      public boolean free;
      public int userQueue;
      public int memberQueue;
      public MutexVar() {free = true; userQueue = memberQueue = 0;}
   }
 
public class Pilot extends Thread
   {
      private String id;
      NoPriorityMonitorKart.MutexVar mutex;
 
      public Pilot(NoPriorityMonitorKart.MutexVar mutex, String
threadName, String id)
      {
         super(threadName);
         this.mutex = mutex;
 
this.id
 = id;
      }
      public Pilot() {}
      public void run()
      {
         Util.rsleep(1500, 2000);
         synchronized(mutex)
         {
            if (id.equals("member"))
            {
               if (mutex.free) mutex.free = false;
               else 
               {
                  mutex.memberQueue++;
                  System.out.println("Placing " + getName() + " in
memberQueue in pos " + mutex.memberQueue + " with " + mutex.userQueue +
" in userQueue.");
                  try {mutex.wait();} catch (InterruptedException e) {};
                  mutex.memberQueue--;
               }
            }
            else
            {
               if (mutex.free) mutex.free = false;
               else
               {
                  mutex.userQueue++;
                  System.out.println("Placing " + getName() + " in
userQueue in pos " + mutex.userQueue + " with " + mutex.memberQueue + "
in memberQueue.");
                  while (!mutex.free || mutex.memberQueue > 0) {try
{mutex.wait();} catch (InterruptedException e) {}};
                  mutex.userQueue--;
               }
            }
         }
         System.out.println(getName() + " has entered the track.");
         Util.rsleep(1500, 2000);
         System.out.println(getName() + " is now exiting.");
         synchronized(mutex)
         {
            /*if (mutex.memberQueue > 0) mutex.memberQueue--;
            else if (mutex.userQueue > 0) mutex.userQueue--;
            else mutex.free = true;*/
            if (mutex.memberQueue == 0 && mutex.userQueue == 0)
mutex.free = true;
            mutex.notifyAll();
         }
      }
   }
 
   public NoPriorityMonitorKart()
   {
      MutexVar mutex = new MutexVar();
 
      for (int i = 0; i < 4; i++) {Thread t = new Pilot(mutex, "pilot" +
(i + 1), "member"); t.start();}
   }
 
   public static void main(String[] args)
   {
      NoPriorityMonitorKart track = new NoPriorityMonitorKart();
   }
}
ciò che non capisco sta nell'output del programma. Ho scritto queste
chiamate nella main:
Thread t = new Pilot(mutex, "member" + 1, "member"); t.start();
t = new Pilot(mutex, "member" + 2, "member"); t.start();
t = new Pilot(mutex, "member" + 3, "member"); t.start();
ed ho avuto questo output:
member1 has entered the track.
Placing member3 in memberQueue in pos 1 with 0 in userQueue.
Placing member2 in memberQueue in pos 2 with 0 in userQueue.
member1 is now exiting.
member3 has entered the track.
member2 has entered the track.
member2 is now exiting.
member3 is now exiting.
Il dubbio è che i thread member3 e member2 vengono risvegliati
praticamente insieme dallo stesso notify:
member3 has entered the track.
member2 has entered the track.
cioè, prima che member3 sia arrivato al suo notify, parte anche member2,
svegliato anch'essod dall'uscita di member1. Come è possibile? Eppure
entrambi devono eseguire:
try {mutex.wait();} catch (InterruptedException e) {};
mutex.memberQueue--;
quindi in mutua esclusione dovrebbero entrarci. Qualcuno mi saprebbe
spiegare questo comportamento?
Scusate il lungo post, grazie mille per qualsiasi suggerimento.
Luca

  {mutex.wait();
prova a scrivere cosi e vedrai che un solo notifyAll non basta piu'
perche' quando la seconda thread prova a ripartire riesegue il while e
rientra in wait
Poi e' chiaro che solo una delle due riesce a prendere il lock e a
ripartire.. ma appena questa esce dal blocco sincronizzato l' altra
puo' prendere il lock e ripartire anche lei, e lo fa sicuramente quando
la prima thread che era ripartita si mette in sleep.
