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
(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 Thread
s 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()
}
}