Exercices

Observation d’ordonnancement

Cet exercice donne des résultats très différents selon les plate-formes (il est intéressant de pouvoir faire des comparaisons).

Copier ce code dans votre espace de travail éventuellement en changeant le nom du package - ou faites en un équivalent en JShell -.

package org.labs.threads;

import java.io.File;
import java.io.IOException;

public class VueOrdonnanceur implements Runnable {

    public static int num =  1 ;
    public final int max ;
    private final int id = num++ ;

    public VueOrdonnanceur( int max){
         this.max = max ;
    }

    @Override
   public String toString() { return "# "+this.id ; }


    @Override
   public void run () {
       for(int ix = 0 ; ix < max ; ix++) {
            try {
                  File temp = File.createTempFile("cpt","") ;
                  System.out.println(this+" ("  + ix + ") :"+temp);
                  temp.delete() ;
            } catch (IOException exc){/* log */}
       }
    }// fin exécution
        // ... autres codes
    public static void main (String[] args) {
      Thread[] tb = new Thread[args.length] ;
      for(int ix = 0 ; ix < tb.length; ix++) {
         tb[ix] = new Thread(new VueOrdonnanceur(Integer.parseInt(args[ix]))) ;
      }

      for(Thread trame : tb) {
         trame.start() ;
      }
   }
}

Lire le code, comprendre ce qu’il fait, le compiler et le tester avec les arguments appropriés. Observer alors la trace d’ordonnancement des Threads.

Actions sur éligibilité

Recopier le code suivant (Modifier le package).

package org.labs.threads;

public class PingPongA {

   public static void main (String[] args) {
      Thread patience = new Thread() {
         public void run() {
            while(!isInterrupted()) {
               System.out.println(" PONG") ;
                //Thread.yield() ;
               /*
                try {
                  Thread.sleep(10) ;
                 } catch(InterruptedException ex) {
                  break ;
                 }
                */
            }
            System.out.println("\nplus de patience") ;
         }
      };
      patience.start() ;
      // Début des actions
      for(int ix = 0 ; ix < 50 ; ix ++) {
         System.out.print("\tPING");
          //Thread.yield() ;
         /*
          try {
            Thread.sleep(10) ;
           } catch(InterruptedException ex) {
            break ;
           }
          */
      }
      patience.interrupt() ;
      try {
          patience.join() ;
         System.out.println("arret") ;
      } catch (InterruptedException exc) {
         System.out.println("arret interruption") ;
      }
   }
}

Dans cet exercice et les suivants on va essayer de faire alterner les PINGS et les PONGS.

Essayer d’abord en utilisant yield

Puis re-faites un essai avec sleep.

Vos conclusions?

Tester le modèle mémoire

../images/blackbelt.png

(exercice de révision)

Voir Ce code

package org.labs.threads;

/**
 * Ce code permet d'exhiber des comportements de gestion
 * de mémoire sur des variables volatiles.
 * L'atomicité des opérations n'est pas garantie.
 */
public class AtomicRW {
   static class TestVolatile implements Runnable {
       static volatile int volatileValueWithOp ;
       static volatile int volatileValuewithIncr ;
       static  int nonVolatileValue ;
       static int max ;
      static volatile int anormalExpr;
      private String id ;
      public TestVolatile(String id){
         this.id = id ;
      }
      public void run() {
         for(int ix = 0 ; ix < max ; ix ++) {
            int val1,val2;
            // Une lecture volatile, Une écriture volatile
            val2 = volatileValueWithOp = 1 + (val1 = volatileValueWithOp) ;
            //val1=  volatileValueWithOp++ ; val2= volatileValueWithOp ;
            val1++ ;
            // Une lecture volatile, Une écriture volatile
            volatileValuewithIncr++ ;
            nonVolatileValue++ ;

            boolean bad = false;
            if( val1 != val2) {
               anormalExpr++ ; // pas atomique
               bad = true ;
            }
            System.out.println(this.id +" " + val1 + " " + val2
               + (bad? " ANORMAL EXPR":""));
         }
      }

   }
   public static void main(String[] args) throws Exception{
      TestVolatile.max = 100000 ;
      Thread t1 = new Thread(new TestVolatile("A")) ;
      Thread t2 = new Thread(new TestVolatile("B")) ;
      t1.start();
      t2.start();
      t1.join() ;
      t2.join() ;
      System.out.println("Anormal expr : " + TestVolatile.anormalExpr);
      if(TestVolatile.volatileValueWithOp != (TestVolatile.max*2)){
         System.out.println(" non executions : "
            + ((TestVolatile.max *2) -TestVolatile.volatileValueWithOp));
      }
      System.out.println(" numbers = (volatile + op) : "
            + TestVolatile.volatileValueWithOp
            + " ; (volatile) :" + TestVolatile.volatileValuewithIncr
            + " ; (non volatile) : " + TestVolatile.nonVolatileValue);
   }

}

l’analyser et le tester sur votre machine.

Blocs synchronized

Reprendre l’exercice "PingPong" précédent et faire en sorte que chaque fois qu’un des Threads commence à afficher un "PING" (ou un "PONG") il soit garanti qu’il puisse afficher 5 fois le même message consécutivement. (exemple : 5 Pings, 5 Pongs, 5 Pings, 5 Pings, etc…) -bien choisir l’objet support de la synchronisation-

Une proposition de solution ICI

Une autre version : ICI

Coordination entre threads

Reprendre l’exercice précédent (séquence de 5 messages) et s’assurer que les messages vont alterner ( 5 pings, 5 pongs, etc.). Alternativement chaque processus se mettra en veille pour ensuite attendre que l’autre le "réveille".

(La solution est très simple, mais n’est pas immédiatement évidente! Pensez à deux sentinelles: l’une dort pendant que l’autre veille; on a trois actions -veiller, dormir, réveiller l’autre- dans quel ordre chacun doit-il les effectuer?).

Une proposition de solution ICI

Un code avec un principe différent ICI

Exemples

Blocs synchronized

package org.labs.threads ;

public class PingPongB {

   public static void main (String[] args) {
      Thread patience = new Thread() {
         public void run() {
            while(!isInterrupted()) {
               synchronized(this) {
                  System.out.println();
                  for(int iy = 0 ; iy <5 ; iy++){
                     System.out.print(" PONG") ;
                  }
               }
               Thread.yield() ;
            }
            System.out.println("\nplus de patience") ;
         }
      };
      patience.start() ;
      // Début des actions
      for(int ix = 0 ; ix < 50 ; ix ++) {
         synchronized(patience) {
            System.out.print("\n\t");
            for(int iy = 0 ; iy <5 ; iy++){
               System.out.print(" PING") ;
            }
         }
         Thread.yield() ;
      }
      patience.interrupt() ;
      try {
          patience.join() ;
         System.out.println("arret") ;
      } catch (InterruptedException exc) {
         System.out.println("arret interruption") ;
      }
   }
}
package org.labs.threads ;

public class PingPongB2 {

   public static void main (String[] args) {
      final Object moniteur = new Object() ;
      Thread patience = new Thread() {
         public void run() {
            while(!isInterrupted()) {
               synchronized(moniteur) {
                  System.out.println();
                  for(int iy = 0 ; iy <5 ; iy++){
                     System.out.print(" PONG") ;
                  }
               }
               Thread.yield() ;
            }
            System.out.println("\nplus de patience") ;
         }
      };
      patience.start() ;
      // Début des actions
      for(int ix = 0 ; ix < 50 ; ix ++) {
         synchronized(moniteur) {
            System.out.print("\n\t");
            for(int iy = 0 ; iy <5 ; iy++){
               System.out.print(" PING") ;
            }
         }
         Thread.yield() ;
      }
      patience.interrupt() ;
      try {
          patience.join() ;
         System.out.println("arret") ;
      } catch (InterruptedException exc) {
         System.out.println("arret interruption") ;
      }
   }
}

Coordination entre threads

package org.labs.threads;

public class PingPongC {

   public static void main (String[] args) {
      final Object moniteur = new Object() ;
      Thread patience = new Thread() {
         public void run() {
            while(!isInterrupted()) {
               synchronized(moniteur) {
                  System.out.println();
                  for(int iy = 0 ; iy <5 ; iy++){
                     System.out.print(" PONG") ;
                  }
                  moniteur.notify() ;
                  try {
                     moniteur.wait() ;
                  } catch(InterruptedException exc){
                     break;
                  }

               }
            }
            System.out.println("\nplus de patience") ;
         }
      };
      patience.start() ;
      // Début des actions
      for(int ix = 0 ; ix < 50 ; ix ++) {
         synchronized(moniteur) {
            System.out.print("\n\t");
            for(int iy = 0 ; iy <5 ; iy++){
               System.out.print(" PING") ;
            }
            moniteur.notify() ;
            try {
               moniteur.wait() ;
            } catch(InterruptedException exc){
               /*IGNORE*/
            }
         }
      }
      patience.interrupt() ;
      try {
          patience.join() ;
         System.out.println("arret") ;
      } catch (InterruptedException exc) {
         System.out.println("arret interruption") ;
      }
   }
}
package org.labs.threads;

public class DingDong implements Runnable{

   private String son ;
   private static Class synchro = DingDong.class ;

   public DingDong(String son) {
      this.son=son;
   }

   public void run() {
      Thread curThread = Thread.currentThread() ;
       while(!curThread.isInterrupted()) {
         synchronized(synchro) {
            synchro.notify() ;
            System.out.print(son+ " ") ;
            System.out.print(son+ " ") ;
            System.out.print(son) ;
            System.out.println() ;
            try{ synchro.wait(); }
            catch(InterruptedException e) {break ; /* TRES IMPORTANT */}
         }// synchronized
      }
      System.out.println( son + " fin!") ;
   }


   public static void main (String[] args) {
      long max = Long.parseLong (args[0]) ;
      Thread ding = new Thread(new DingDong("ding")) ;
      Thread dong = new Thread(new DingDong("DONG")) ;
      // avec 3 l'ordre n'est plus garanti
      // seulement alternance
      // Thread dang = new Thread(new DingDong("DANG")) ;
      ding.start() ; dong.start() ;
      // dang.start() ;
      try {
         Thread.sleep(max) ;
      } catch (InterruptedException exc) { /*IGNORE */ }
      ding.interrupt() ;
      dong.interrupt() ;
      //dang.interrupt()
   }
}