voisin-polian : introduction à java 1 introduction à java - les « threads » - frédéric voisin...

27
Voisin-Polian : Introduction à Java 1 Introduction à Java - les « Threads » - Frédéric VOISIN – Nicole POLIAN FIIFO - « Remise à Niveau »

Upload: jacquette-gueguen

Post on 03-Apr-2015

110 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: Voisin-Polian : Introduction à Java 1 Introduction à Java - les « Threads » - Frédéric VOISIN – Nicole POLIAN FIIFO - « Remise à Niveau »

Voisin-Polian : Introduction à Java 1

Introduction à Java

- les « Threads » -

Frédéric VOISIN – Nicole POLIAN

FIIFO - « Remise à Niveau »

Page 2: Voisin-Polian : Introduction à Java 1 Introduction à Java - les « Threads » - Frédéric VOISIN – Nicole POLIAN FIIFO - « Remise à Niveau »

Voisin-Polian : Introduction à Java 2

Les « Threads » Java (ou « processus légers »)

Ils permettent de lancer plusieurs tâches en même temps au sein d’un même processus

Ils permettent de refléter des découpages logiques en composants s’exécutant indépendamment ou en coopération

Ils sont utilisés en interne par Java : le ramasse-miette est un thread de faible priorité, la méthode main(String[] args) s’exécute dans un thread …

Les threads partagent la même zone mémoire, ce qui facilite la communication entre threads. Le temps de commutation entre threads est inférieur à celui des processus.

Page 3: Voisin-Polian : Introduction à Java 1 Introduction à Java - les « Threads » - Frédéric VOISIN – Nicole POLIAN FIIFO - « Remise à Niveau »

Voisin-Polian : Introduction à Java 3

Exemple (presque) sans thread

public class Train { int vitesse; String nom; public Train(int v, String n){ vitesse = v; nom = n;} public void run() { System.out.println(nom + " part"); try { Thread.currentThread().sleep(vitesse*500); } catch (InterruptedException e) {} System.out.println(nom + " roule"); try { Thread.currentThread().sleep(vitesse*50); } catch (InterruptedException e) {} System.out.println(nom + " s'arrete"); }}

La méthode main s’exécute dans un thread !Le déroulement de sleep pourrait être abrégé par une « interruption », d’où le try/catch

Page 4: Voisin-Polian : Introduction à Java 1 Introduction à Java - les « Threads » - Frédéric VOISIN – Nicole POLIAN FIIFO - « Remise à Niveau »

Voisin-Polian : Introduction à Java 4

Exemple sans thread (suite)

// lancement de trois trains de vitesses différentes

public class TestTrain { public static void main (String[] args) { Train micheline = new Train(50, "MICHELINE"); Train tgv = new Train(10, "TGV"); Train corail = new Train(20, "CORAIL");

micheline.run(); tgv.run (); corail.run(); System.out.println("fin du main"); }}

MICHELINE part MICHELINE roule MICHELINE s'arrete TGV part TGV roule TGV s'arrete CORAIL part CORAIL roule CORAIL s'arrete fin du main

Page 5: Voisin-Polian : Introduction à Java 1 Introduction à Java - les « Threads » - Frédéric VOISIN – Nicole POLIAN FIIFO - « Remise à Niveau »

Voisin-Polian : Introduction à Java 5

Exemple avec thread

public class Test { public static void main(String[] args) { Train tgv = new Train(10, "TGV"); Train corail = new Train(20,"CORAIL"); Train micheline = new train (50, "MICHELINE"); micheline.start(); tgv.start(); corail.start(); System.out.println("Threads actifs : " + Thread.currentThread().activeCount());

try { corail.join(); // attendre la fin de corail ! } catch (InterruptedException ex) { } System.out.println("Threads actifs : " + Thread.currentThread().activeCount());

System.out.println("fin du main"); }}

Page 6: Voisin-Polian : Introduction à Java 1 Introduction à Java - les « Threads » - Frédéric VOISIN – Nicole POLIAN FIIFO - « Remise à Niveau »

Voisin-Polian : Introduction à Java 6

Exemple avec thread (suite)

class Train extends Thread { int vitesse; public Train(int v, String n) { super(n); // permet de « nommer » le thread. // getName() renvoie le nom ! vitesse = v; } public void run() { System.out.println(getName() + " part"); try { sleep(vitesse*500); } catch(InterruptedException e) { } System.out.println(getName() + " roule"); try { sleep(vitesse*50); } catch(InterruptedException e) { } System.out.println(getName() + " s'arrete"); }}

Exemple d’exécution

Threads actifs : 4MICHELINE partTGV partCORAIL partTGV roule TGV s'arreteCORAIL roule CORAIL s'arreteThreads actifs : 2 fin du mainMICHELINE roule MICHELINE s'arrete

Page 7: Voisin-Polian : Introduction à Java 1 Introduction à Java - les « Threads » - Frédéric VOISIN – Nicole POLIAN FIIFO - « Remise à Niveau »

Voisin-Polian : Introduction à Java 7

Le principe des Threads

La classe Train dérive de la classe Thread.

La méthode start démarre le thread, ce qui entraîne l’appel de la méthode

run. Le thread termine quand il atteint la fin de la méthode run.

La méthode join permet de se synchroniser avec la fin d’un thread.

Une autre synchronisation serait nécessaire si le thread produisait des résultats à récupérer (à voir après)

L’héritage multiple n’existant pas en Java, il existe un deuxième mécanisme pour utiliser les threads : l’utilisation de l’interface Runnable, qui impose l’existence d’une méthode run. On passe alors une instance d’une classe qui implémente Runnable comme premier argument au constructeur de Thread.

Page 8: Voisin-Polian : Introduction à Java 1 Introduction à Java - les « Threads » - Frédéric VOISIN – Nicole POLIAN FIIFO - « Remise à Niveau »

Voisin-Polian : Introduction à Java 8

Utilisation de l’interface Runnable

public class Test {

public static void main(String[] args) {Thread tgv = new Thread(new Train(10, "TGV"));

Thread corail = new Thread(new Train(20, "CORAIL"));

Thread micheline = new Thread(new Train(50, "MICHELINE"));

micheline.start(); tgv.start(); corail.start();

System.out.println("fin du main") ;

}

}

// le paramètre du constructeur de Thread doit implémenter l’interface Runnable !

Page 9: Voisin-Polian : Introduction à Java 1 Introduction à Java - les « Threads » - Frédéric VOISIN – Nicole POLIAN FIIFO - « Remise à Niveau »

Voisin-Polian : Introduction à Java 9

Utilisation de l’interface Runnable (suite)

public class Train implements Runnable {int v; String nom;public Train(int i, String n) { v = i; nom = n;}public void run() { System.out.println(nom + " part"); try { Thread.currentThread().sleep(v*500); } catch(InterruptedException e) {} System.out.println(nom + " roule"); try { Thread.currentThread().sleep(v*50); } catch(InterruptedException e) {} System.out.println(nom + " s'arrete");}

}

fin du main

MICHELINE part

TGV part

CORAIL part

TGV roule

TGV s'arrete

CORAIL roule

CORAIL s'arrete

MICHELINE roule

MICHELINE s'arrete

Page 10: Voisin-Polian : Introduction à Java 1 Introduction à Java - les « Threads » - Frédéric VOISIN – Nicole POLIAN FIIFO - « Remise à Niveau »

Voisin-Polian : Introduction à Java 10

Les états d’un Thread

créé

actifEn attente

mort

new ( )

terminaison

start ( )

wait ( ) ou sleep ( )

notify ( ) ou interruption

Page 11: Voisin-Polian : Introduction à Java 1 Introduction à Java - les « Threads » - Frédéric VOISIN – Nicole POLIAN FIIFO - « Remise à Niveau »

Voisin-Polian : Introduction à Java 11

Les principales méthodes liées aux threads

statiques : currentThread()activeCount() // threads démarrés et pas encore mortsenumerate() // permet de les copier dans un tableau

// Thread[] th=new Thread[nb];nb=Thread.enumerate(th);yield() // rend la main volontairement pour un autre threadsleep() // ne relâche pas les moniteurs (cf. infra)

non statiquesisAlive()join()setDaemon() // à faire avant start() !isDaemon()

dans Object // pour les moniteurs (synchronisation de threads)wait // en attente de notificationnotify // notification

« Deprecated » (induisent de forts risques de deadlock, cf. infra)stop, suspend, resume

Page 12: Voisin-Polian : Introduction à Java 1 Introduction à Java - les « Threads » - Frédéric VOISIN – Nicole POLIAN FIIFO - « Remise à Niveau »

Voisin-Polian : Introduction à Java 12

Exemple de Thread

public class Heure1 extends Frame { // utilisation de AWT !!

Label l1, l2, h1, h2; Button arret1; Timer1 t1, t2;

Heure1() {

setLayout(new FlowLayout());

l1 = new Label (" ");

l2 = new Label (" ");

l1.setBackground(Color.white); l2.setBackground(Color.white);

l1.setAlignment(Label.CENTER); l2.setAlignment(Label.CENTER);

Font f = new Font("TimesRoman", Font.PLAIN, 18); setFont(f);

arret1 = new Button ("STOP");

h1 = new Label("MONTREAL"); h2 = new Label("PARIS");

ActionListener larret1 = new ActionListener() {

public void actionPerformed(ActionEvent e){ System.exit(1);}

}; // classe interne, définie au vol !

… // ActionListener est une interface associée aux événements click sur les boutons

Page 13: Voisin-Polian : Introduction à Java 1 Introduction à Java - les « Threads » - Frédéric VOISIN – Nicole POLIAN FIIFO - « Remise à Niveau »

Voisin-Polian : Introduction à Java 13

Exemple de Thread (suite)

arret1.addActionListener(larret1); // associe action/bouton add(arret1); // ajout des composants add(l1); add(h1); // à l’instance de Frame add(l2); add(h2); t1 = new Timer1(l1, 1); t2 = new Timer1(l2, 2); t1.start(); t2.start(); } // fin de Heure1()

public static void main(String[] args) { Heure1 t = new Heure1(); t.setBounds(20, 20, 800, 60); t.setVisible(true);}

}

Page 14: Voisin-Polian : Introduction à Java 1 Introduction à Java - les « Threads » - Frédéric VOISIN – Nicole POLIAN FIIFO - « Remise à Niveau »

Voisin-Polian : Introduction à Java 14

Exemple de Thread (suite)

public class Timer1 extends Thread {Label l; int type; Date maDate;SimpleDateFormat mF = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss");

public Timer1(Label l, int t) { this.l = l; type = t; }

public void run() { while (true) { try { sleep (2000); } catch(InterruptedException e) {} maDate = new Date(); if (type == 1) { mF.setTimeZone(TimeZone.getTimeZone("America/Montreal")); L.setText(mF.format(maDate)); } else { mF.setTimeZone(TimeZone.getTimeZone("Europe/Paris")); L.setText(mF.format(maDate)); } }

}

Page 15: Voisin-Polian : Introduction à Java 1 Introduction à Java - les « Threads » - Frédéric VOISIN – Nicole POLIAN FIIFO - « Remise à Niveau »

Voisin-Polian : Introduction à Java 15

Les démons (« daemon »)

Il existe deux sortes de threads les threads ordinaires (utilisateurs) les threads démons (notamment créés par la JVM; exemple : le ramasse-miettes)

deux méthodes setDaemon(boolean b) // à exécuter avant start boolean isDaemon()

Un « processus » Java s’arrête lorsqu’il ne reste plus que des threads démons. Ceux-ci correspondent à des threads « de service » qui ne contribuent pas directement à la logique applicative.

Page 16: Voisin-Polian : Introduction à Java 1 Introduction à Java - les « Threads » - Frédéric VOISIN – Nicole POLIAN FIIFO - « Remise à Niveau »

Voisin-Polian : Introduction à Java 16

L’ordonnancement (scheduling)

Question : quel thread a la main ?celui qui a la plus grande priorité parmi les threads actifs !

pour changer la priorité : getPriority() setPriority()

Thread.MIN_PRIORITY Thread.MAX_PRIORITY Thread.NORM_PRIORITY

En cas d’égalité, certaines implémentation laissent la main au thread en cours (pas d’équité entre les threads potentiellement activables).

Dans ce cas, il faut utiliser la méthode yield() ou bien sleep(0) pour relâcher la main.

Page 17: Voisin-Polian : Introduction à Java 1 Introduction à Java - les « Threads » - Frédéric VOISIN – Nicole POLIAN FIIFO - « Remise à Niveau »

Voisin-Polian : Introduction à Java 17

Arrêter un Thread

public class TestArret { public static void main(String[] args) { tt = new Train(); tt.start(); try { Thread.currentThread().sleep(2000); tt.stoppe(); tt.join(); } catch (InterruptedException ex) {} System.out.println("fin du main"); }

} class Train extends Thread { private boolean arrete = false; public void run() { while (! arrete) { System.out.println("le train roule"); try { sleep(500);} catch(InterruptedException e) {} } System.out.println("le train s'arrete"); } public void stoppe() { arrete = true ; }

} // accès sans précaution à arrete ;-(

le train roule

le train roule

le train roule

le train roule

le train s'arrete

fin du main

Page 18: Voisin-Polian : Introduction à Java 1 Introduction à Java - les « Threads » - Frédéric VOISIN – Nicole POLIAN FIIFO - « Remise à Niveau »

Voisin-Polian : Introduction à Java 18

Problèmes de synchronisation

Les threads partagent les mêmes données et agissent sur les mêmes objets problèmes d’accès incohérents aux données

On peut protéger une suite d’instruction (ou une fonction) avec synchronized

Pour une fonction : à tout instant il s’exécute au plus une fonction synchronized sur un objet donné… mais les fonctions non synchronized n’ont aucune obligation synchronized int fonct() { …}

Par « verrouillage » d’un objet (arbitraire) pour une suite d’instructions arbitraire :synchronized (obj) { // au plus une séquence d’instructions ou méthode

// synchronized à la fois sur obj. obj.action(); … }

Reprend les principes des moniteurs de Hoare/Brinch Hansen

Page 19: Voisin-Polian : Introduction à Java 1 Introduction à Java - les « Threads » - Frédéric VOISIN – Nicole POLIAN FIIFO - « Remise à Niveau »

Voisin-Polian : Introduction à Java 19

Exemple de synchronisation

class Truc {int val = 0;void incr(int tempo) { int i = val; try { Thread.currentThread().sleep(tempo); } catch (InterruptedException e) {} val = i+1; // la valeur de val il y a un certain temps ! try { Thread.currentThread().sleep(tempo) ; } catch (InterruptedException ex) { } ; }public String toString() { return "valeur " + val;}}

class Collision {static truc cpt = new truc();public static void main(String[] arg) { Compteur t1 = new Compteur(cpt,1); Compteur t2 = new Compteur(cpt,2); t1.start(); t2.start(); try { t1.join(); t2.join(); } catch (InterruptedException ex) {}; System.out.println("fin du main : " + cpt); }}

Page 20: Voisin-Polian : Introduction à Java 1 Introduction à Java - les « Threads » - Frédéric VOISIN – Nicole POLIAN FIIFO - « Remise à Niveau »

Voisin-Polian : Introduction à Java 20

Exemple de synchronisation (suite)

class Compteur extends Thread {int num; truc cpt; Random rd;public Compteur (truc c, int nm) { num = nm; cpt = c; rd = new Random(nm);}

public void run() { System.out.println("debut run " + num); for(int i = 0; i<100; i++) { // synchronized(cpt) { cpt.incr(Math.abs(rd.nextInt())); } } System.out.println ("fin run " + num);}

}

sans synchronized(cpt) debut run 1 debut run 2 fin run 1 fin run 2 fin du main : valeur 143

avec synchronized(cpt) debut run 1 debut run 2 fin run 1 fin run 2 fin du main : valeur 200

Page 21: Voisin-Polian : Introduction à Java 1 Introduction à Java - les « Threads » - Frédéric VOISIN – Nicole POLIAN FIIFO - « Remise à Niveau »

Voisin-Polian : Introduction à Java 21

Les appels wait et notify

wait bloque l’exécution du thread jusqu’à réception d’une « notification » envoyée par un autre thread. Le verrou sur l’objet est levé (à la différence de sleep !)

notify envoie la notification précédente : « réveil » du (ou plutôt d’un) thread bloqué. notifyAll() réveille tous les threads bloqués sur cet objet.

Attention: les threads débloqués doivent encore « acquérir » l’objet sur lequel ils se synchronisent. Ils sont en concurrence avec tous les autres threads similaires (pas de privilège d’accès). Souvent on doit englober le wait dans une boucle d’accès en attendant qu’une certaine condition soit effectivement réalisée.

Attention aux deadlocks, si on acquiert les objets dans le désordre ou si on oublie d’en libérer l’accès !

Page 22: Voisin-Polian : Introduction à Java 1 Introduction à Java - les « Threads » - Frédéric VOISIN – Nicole POLIAN FIIFO - « Remise à Niveau »

Voisin-Polian : Introduction à Java 22

wait et notify (suite)

synchronized ( obj ) {

obj.wait ( ) ;

}

synchronized ( obj ) {

obj.notify ( ) ;

}

T1..

T2..

.

.

.

.

.

.

réveil

L’attente se fait « sur »  un objet. Le notify est envoyé à ce même objet.

L’objet doit « appartenir » au thread qui exécute wait/notify, cela implique l’utilisation obligatoire de synchronized. Gérer le verrou sur un objet nécessite d’acquérir cet objet !

Page 23: Voisin-Polian : Introduction à Java 1 Introduction à Java - les « Threads » - Frédéric VOISIN – Nicole POLIAN FIIFO - « Remise à Niveau »

Voisin-Polian : Introduction à Java 23

Un Exemple

public class Heure2 extends Frame { Label l1, l2; Button h1, h2, arret1; Timer2 t1, t2;

Heure2() { setLayout(new FlowLayout()); l1 = new Label(" "); l2 = new Label(" "); l1.setBackground(Color.white); l2.setBackground(Color.white); l1.setAlignment(Label.CENTER); l2.setAlignment(Label.CENTER); Font f = new Font("TimesRoman", Font.PLAIN, 18); setFont(f); arret1 = new Button("Stop Montreal"); h1 = new Button("MONTREAL"); h2 = new Button("PARIS"); ActionListener larret1 = new ActionListener() { public void actionPerformed(ActionEvent e) { t1.stoppe(); // arret definitif de l'horloge locale remove(l1); remove(h1); remove(arret); }};…

Page 24: Voisin-Polian : Introduction à Java 1 Introduction à Java - les « Threads » - Frédéric VOISIN – Nicole POLIAN FIIFO - « Remise à Niveau »

Voisin-Polian : Introduction à Java 24

Un Exemple (suite)

ActionListener lh2 = new ActionListener() { public void actionPerformed(ActionEvent e) { if (! t2.isAlive()) { t2.start(); } }} ; ActionListener lh1 = new ActionListener() { public void actionPerformed(ActionEvent e) { if (! t1.isAlive()) { t1.start(); } else { t1.bascule(); } }};

arret1.addActionListener(larret1); h1.addActionListener(lh1; h2.addActionListener(lh2); add(arret1); add(l1); add(h1); add(l2); add(h2); t1 = new Timer2(l1, 1); t2 = new Timer2(lab2, 2);}public static void main(String[] arg) { Heure2 t = new Heure2(); t.setBounds(20, 20, 800, 60); t.setVisible(true);}

}

Page 25: Voisin-Polian : Introduction à Java 1 Introduction à Java - les « Threads » - Frédéric VOISIN – Nicole POLIAN FIIFO - « Remise à Niveau »

Voisin-Polian : Introduction à Java 25

Un Exemple (suite)

class Timer2 extends Thread { Label L; int type; boolean marche, actif;

public Timer2(Label l, int t) { L = l; type = t; marche = true; actif = true; }

public void stoppe() { marche = false; }

public void bascule() { if (actif) { actif = false ; } else { synchronized(L) { L.notify(); } } }

Page 26: Voisin-Polian : Introduction à Java 1 Introduction à Java - les « Threads » - Frédéric VOISIN – Nicole POLIAN FIIFO - « Remise à Niveau »

Voisin-Polian : Introduction à Java 26

Un Exemple (suite)

public void run() { Date maDate; SimpleDateFormat mF=new SimpleDateFormat("dd-MMM-yyyyHH:mm:ss"); while (marche) { try { sleep (2000); } catch (InterruptedException ex) {} if (! actif) { try { synchronized(L) { L.wait(); } } catch (InterruptedException ex) {} actif = true ; } maDate = new Date(); if (type == 1){ mF.setTimeZone(TimeZone.getTimeZone("America/Montreal")); L.setText(monFormat.format(maDate)); } else { mF.setTimeZone(TimeZone.getTimeZone("Europe/Paris")); L.setText(mF.format(maDate)); } }}}

Page 27: Voisin-Polian : Introduction à Java 1 Introduction à Java - les « Threads » - Frédéric VOISIN – Nicole POLIAN FIIFO - « Remise à Niveau »

Voisin-Polian : Introduction à Java 27

Un Exemple (affichage)