IFT 1025 Programmation 2 MultiThread JianYun Nie 1

  • Slides: 38
Download presentation
IFT 1025 – Programmation 2 Multi-Thread Jian-Yun Nie 1

IFT 1025 – Programmation 2 Multi-Thread Jian-Yun Nie 1

Concepts • Thread: – Unité de programme qui est exécuté en parallèle avec le

Concepts • Thread: – Unité de programme qui est exécuté en parallèle avec le reste des programmes • Processus en parallèle – Plusieurs processus sont exécutés en même temps • Créer, lancer et terminer un thread • Interface Runnable • Synchronisation des threads 2

Interface Runnable • Une méthode run() exigée: public interface Runnable { void run(); }

Interface Runnable • Une méthode run() exigée: public interface Runnable { void run(); } • Implantation: public class My. Runnable implements Runnable { public void run() { // Task statements go here . . . } } 3

Créer un thread Un Thread est une classe qui implante Runnable 1. Créer une

Créer un thread Un Thread est une classe qui implante Runnable 1. Créer une sous-classe de Thread (doit aussi implanter run() ) class Prime. Thread extends Thread { long min. Prime; Prime. Thread(long min. Prime) { this. min. Prime = min. Prime; } public void run() { // compute primes larger than min. Prime . . . } } Utilisation: Prime. Thread p = new Prime. Thread(143); p. start(); 4

Créer un thread 2. Un thread est créé à base d’un objet Runnable r

Créer un thread 2. Un thread est créé à base d’un objet Runnable r = new My. Runnable(); Thread t = new Thread(r); t. start(); 5

Classe Thread public class Thread extends Object implements Runnable Constructeurs: Thread() Thread(Runnable target) Thread(String

Classe Thread public class Thread extends Object implements Runnable Constructeurs: Thread() Thread(Runnable target) Thread(String name) … 6

Classe Thread • Méthodes: static int active. Count(): nb. de threads de ce groupe

Classe Thread • Méthodes: static int active. Count(): nb. de threads de ce groupe void destroy() void interrupt() static void sleep(long millis) void start() static void yield(): faire une pause et permettre aux autres threads d’exécuter (traitement de deadlock) … 7

Explication de thread Séquence d’actions • Bien ordonnée en parallèle 8

Explication de thread Séquence d’actions • Bien ordonnée en parallèle 8

Exemple 1: Définition de Thread • Créer une sous-classe de Thread: public class Simple.

Exemple 1: Définition de Thread • Créer une sous-classe de Thread: public class Simple. Thread extends Thread { public Simple. Thread(String str) { super(str); } public void run() { for (int i = 0; i < 10; i++) { System. out. format("%d %s%n", i, get. Name()); try { sleep((long)(Math. random() * 1000)); } catch (Interrupted. Exception e) {} System. out. format("DONE! %s%n", get. Name()); } } Thread avec un nom Méthode run(): 10 fois: Afficher le nom du Thread et sleep un temps aléatoire 9

Exemple 1: Utilisation du Thread • Lancer 2 Threads public class Two. Threads. Test

Exemple 1: Utilisation du Thread • Lancer 2 Threads public class Two. Threads. Test { public static void main (String[] args) { new Simple. Thread("Jamaica"). start(); new Simple. Thread("Fiji"). start(); } } 10

Différence avec un appel à run() public class Two. Threads. Test { public static

Différence avec un appel à run() public class Two. Threads. Test { public static void main (String[] args) { new Simple. Thread("Jamaica"). run(); new Simple. Thread("Fiji"). run(); } } 0 Jamaica 1 Jamaica 2 Jamaica 3 Jamaica 4 Jamaica 5 Jamaica 6 Jamaica 7 Jamaica 8 Jamaica 9 Jamaica DONE! Jamaica 0 Fiji 1 Fiji 2 Fiji 3 Fiji 4 Fiji 5 Fiji 6 Fiji 7 Fiji 8 Fiji 9 Fiji DONE! Fiji 11

Exemple 2: Clock public import java. awt. *; import java. util. *; import java.

Exemple 2: Clock public import java. awt. *; import java. util. *; import java. applet. *; import java. text. *; public class Clock extends java. applet. Applet implements Runnable { private volatile Thread clock. Thread = null; Date. Format formatter; //Formats the date displayed String lastdate; //String to hold date displayed Date current. Date; //Used to get date to display Color number. Color; //Color of numbers Font clock. Face. Font; Locale locale; public void init() { set. Background(Color. white); number. Color = Color. red; locale = Locale. get. Default(); formatter = Date. Format. get. Date. Time. Instance(Date. Format. FULL, Date. Format. MEDIUM, locale); current. Date = new Date(); lastdate = formatter. format(current. Date); clock. Face. Font = new Font("Sans-Serif", Font. PLAIN, 14); resize(275, 25); } public void start() { if (clock. Thread == null) { start de Applet clock. Thread = new Thread(this, "Clock"); clock. Thread. start(); } } start de Thread – run() Tant que non-fini, reffiche toute les secondes void run() { Thread my. Thread = Thread. current. Thread(); while (clock. Thread == my. Thread) { repaint(); try { Thread. sleep(1000); } catch (Interrupted. Exception e){ } } } public void paint(Graphics g) { String today; current. Date = new Date(); Temps courant formatter = Date. Format. get. Date. Time. Instance(Date. Format. FULL, Date. Format. MEDIUM, locale); today = formatter. format(current. Date); g. set. Font(clock. Face. Font); //Erase and redraw g. set. Color(get. Background()); g. draw. String(lastdate, 0, 12); g. set. Color(number. Color); g. draw. String(today, 0, 12); lastdate = today; current. Date = null; } public void stop() { clock. Thread = null; } } stop: si la fenêtre ferme 12

Déclarer Thread avec Thread ou Runnable? 1. Créer une sous-classe de Thread 2. Créer

Déclarer Thread avec Thread ou Runnable? 1. Créer une sous-classe de Thread 2. Créer un Thread avec Runnable • Les 2 méthodes sont possibles • Utiliser la 2 -ième méthode si le Thread doit être une sous-classe d’une autre classe (e. g. Clock) – La première méthode ne le permet pas – Une classe ne peut pas avoir 2 super-classes 13

États d’un Thead • Création et lancement: public void start() { if (clock. Thread

États d’un Thead • Création et lancement: public void start() { if (clock. Thread == null) { clock. Thread = new Thread(this, "Clock"); clock. Thread. start(); } } • • • Entrer dans Runnable Not Runnable: sleep(), E/S Dead: terminaison: Fermer Applet -> exécuter stop() public void stop() { //applet's stop method clock. Thread = null; } 14

Terminer un Thread Schéma typique: public void run() { try { for (int i

Terminer un Thread Schéma typique: public void run() { try { for (int i = 1; i <= REPETITIONS; i++) { // Do work } } catch (Interrupted. Exception exception) { // Clean up } } 15

Exemple public class My. Runnable implements Runnable { public void run() { try {

Exemple public class My. Runnable implements Runnable { public void run() { try { System. out. println(1); Thread. sleep(1000); System. out. println(2); } catch (Interrupted. Exception exception) { System. out. println(3); } System. out. println(4); } } • Sortie? 1, 3, 4 16

Détecter l’état d’un Thread • Thread. get. State(): – NEW – RUNNABLE – BLOCKED

Détecter l’état d’un Thread • Thread. get. State(): – NEW – RUNNABLE – BLOCKED – WAITING – TIMED_WAITING – TERMINATED 17

Synchronisation +2 *1. 02 X -100 -20 Accès conflictuels: écrire lire (put - producer)

Synchronisation +2 *1. 02 X -100 -20 Accès conflictuels: écrire lire (put - producer) (get -consumer) 18

Exemple: Accéder au même Bank. Acount public class Deposit. Runnable implements Runnable { public

Exemple: Accéder au même Bank. Acount public class Deposit. Runnable implements Runnable { public void run() { try { for (int i = 1; i <= count; i++) { account. deposit(amount); Thread. sleep(DELAY); } } catch (Interrupted. Exception exception) { } } … public class Withdraw. Runnable implements Runnable { public void run() { try { for (int i = 1; i <= count; i++) { account. withdraw(amount); Thread. sleep(DELAY); } } catch (Interrupted. Exception exception) { } } … 19

new Deposit. Runnable(). start(); new Withdraw. Runnable(). start(); Depositing 100. 0, new balance is

new Deposit. Runnable(). start(); new Withdraw. Runnable(). start(); Depositing 100. 0, new balance is 100. 0 Withdrawing 100. 0, new balance is 0. 0 . . . Withdrawing 100. 0, new balance is 400. 0 Depositing 100. 0, new balance is 500. 0 Withdrawing 100. 0, new balance is 400. 0 Withdrawing 100. 0, new balance is 300. 0 Problème Depositing 100. 0 Withdrawing 100. 0, new balance is 100. 0, new balance is -100. 0 20

Synchronisation: Solution 1 • Bloquer la ressource durant un traitement: public class Bank. Account

Synchronisation: Solution 1 • Bloquer la ressource durant un traitement: public class Bank. Account { public Bank. Account() { balance. Change. Lock = new Reentrant. Lock(); . . . } . . . private Lock balance. Change. Lock; } • Utilisation typique: – balance. Change. Lock. lock(); – Code that manipulates the shared resource – balance. Change. Lock. unlock(); 21

Utilisation typique Toujours dans Bank. Account public void deposit(double amount) { balance. Change. Lock.

Utilisation typique Toujours dans Bank. Account public void deposit(double amount) { balance. Change. Lock. lock(); try { System. out. print("Depositing " + amount); double new. Balance = balance + amount; System. out. println(", new balance is " + new. Balance); balance = new. Balance; } finally Finally: Pour que ça { fonctionne même si une balance. Change. Lock. unlock(); exception est lancée } } 22

Interface Lock • void lock(): bloquer la ressource • Condition new. Condition(): associer une

Interface Lock • void lock(): bloquer la ressource • Condition new. Condition(): associer une condition (plus tard) • void unlock(): débloquer Les classes qui implante l’interface Lock: Reentrant. Lock, Reentrant. Read. Write. Lock. Read. Lock, Reentrant. Read. Write. Lock 23

Schéma général • Bloquer • Exécuter un bloc (try) • Débloquer (finally) Lock l

Schéma général • Bloquer • Exécuter un bloc (try) • Débloquer (finally) Lock l =. . . ; l. lock(); try { // access the resource protected by this lock } finally { l. unlock(); } 24

Reentrant. Lock • Une classe qui implante Lock • Plus de méthodes que celles

Reentrant. Lock • Une classe qui implante Lock • Plus de méthodes que celles exigées dans Lock class X { private final Reentrant. Lock lock = new Reentrant. Lock(); //. . . public void m() { lock(); // block until condition holds try { //. . . method body } finally { lock. unlock() } } } 25

Synchronisation: Solution 2 synchronized: réalise block, try [bloc], finally {unlock} public class Bank. Account

Synchronisation: Solution 2 synchronized: réalise block, try [bloc], finally {unlock} public class Bank. Account { public synchronized void deposit(double amount) { System. out. print("Depositing " + amount); double new. Balance = balance + amount; System. out. println(", new balance is " + new. Balance); balance = new. Balance; } public synchronized void withdraw(double amount) { System. out. print("Withdrawing " + amount); double new. Balance = balance - amount; System. out. println(", new balance is " + new. Balance); balance = new. Balance; } … 26

Problème de Deadlock • 2 ou plus Threads attendent qu’un autre thread débloque une

Problème de Deadlock • 2 ou plus Threads attendent qu’un autre thread débloque une ressource nécessaire Possède A Possède B Possède C Demande B Demande C Demande A 27

Une solution à Deadlock (façon 1) • Objet Condition associé à un Lock public

Une solution à Deadlock (façon 1) • Objet Condition associé à un Lock public class Bank. Account { public Bank. Account() //Constructeur { balance. Change. Lock = new Reentrant. Lock(); sufficient. Funds. Condition = balance. Change. Lock. new. Condition(); . . . } . . . private Lock balance. Change. Lock; private Condition sufficient. Funds. Condition; } 28

Une solution à Deadlock • Un retrait attend la condition nécessaire public void withdraw(double

Une solution à Deadlock • Un retrait attend la condition nécessaire public void withdraw(double amount) { balance. Change. Lock. lock(); try { while (balance < amount) sufficient. Funds. Condition. await(); . . . } finally { balance. Change. Lock. unlock(); } } 29

Effets de await() sufficient. Funds. Condition. await(); • Attendre la ressource nécessaire (suffisamment d’argent)

Effets de await() sufficient. Funds. Condition. await(); • Attendre la ressource nécessaire (suffisamment d’argent) • Relâche l’objet bloqué en attendant (Bank. Account) – Permet aux autres threads d’exécuter • L’attente se réveille quand il reçoit un signal – signal. All() 30

Une solution à Deadlock • Un retrait attend la condition nécessaire public void withdraw(double

Une solution à Deadlock • Un retrait attend la condition nécessaire public void withdraw(double amount) { balance. Change. Lock. lock(); try { while (balance < amount) sufficient. Funds. Condition. await(); . . . // faire le retrait } finally { balance. Change. Lock. unlock(); } } Le thread attend, relâche l’objet Bank. Acount, attend d’être signalé (ou interrompu) Quand il est signalé, on doit tester encore la condition balance < amount 31

Une solution à Deadlock • Un dépôt signale à tous les Thread que la

Une solution à Deadlock • Un dépôt signale à tous les Thread que la condition est possiblement changée public void deposit(double amount) { balance. Change. Lock. lock(); try { System. out. print("Depositing " + amount); double new. Balance = balance + amount; System. out. println(", new balance is " + new. Balance); balance = new. Balance; sufficient. Funds. Condition. signal. All(); } finally { balance. Change. unlock(); } } 32

Condition • Construction à partir d’un Lock: – Lock. new. Condition() • Méthodes de

Condition • Construction à partir d’un Lock: – Lock. new. Condition() • Méthodes de Condition: – void await(): attend d’être signalé ou interrompu – void signal(): réveille un thread qui attend – void signal. All(): réveille tous les threads qui attendent 33

Résumé class Ressource { Lock l; Condition c = l. new. Condition(); public void

Résumé class Ressource { Lock l; Condition c = l. new. Condition(); public void methode 1 //consumer { l. lock(); try { while (…) c. await(); … } finally {l. unlock(); } } public void methode 2 //producer { l. lock(); try { …, signal. All(); } finally {l. unclock(); } Méthode qui attend une condition Méthode qui peut satisfaire ne condition d’un autre thread … } 34

Sortir de Deadlock (façon 2) • Thread. yield() – static void yield(); – Pause

Sortir de Deadlock (façon 2) • Thread. yield() – static void yield(); – Pause du thread courant, et permet aux autres threads d’exécuter • Utilisation typique – Si le thread ne dispose qu’une partie de resource, et l’autre partie n’est pas disponible: • relâcher la ressource retenu (la rendre disponible) • Thread. yield(); // permet aux autres d’exécuter 35

Les méthodes dans Object • Les méthodes de Object permettent aussi de synchroniser les

Les méthodes dans Object • Les méthodes de Object permettent aussi de synchroniser les threads: – void wait(): attendre – void notify(): signale un Thread qui attend qu’il y a eu un changement – void notify. All(): signale à tous les Threads 36

Exemple de deadlock • Les deux méthodes bloquent public synchronized int get() { //Won't

Exemple de deadlock • Les deux méthodes bloquent public synchronized int get() { //Won't work! if (available == true) { available = false; return contents; } } public synchronized void put(int value) { //Won't work! if (available == false) { available = true; contents = value; } } 37

Solution à Deadlock (façon 3) public synchronized int get() { while (available == false)

Solution à Deadlock (façon 3) public synchronized int get() { while (available == false) { try { //Wait for Producer to put value. wait(); } catch (Interrupted. Exception e) { } } available = false; //Notify Producer that value has been retrieved. notify. All(); return contents; } Tant que la condition n’est pas vraie, wait(): public synchronized void put(int value) { while (available == true) { try { //Wait for Consumer to get value. wait(); } catch (Interrupted. Exception e) { } } contents = value; available = true; //Notify Consumer that value has been set. notify. All(); } notify. All(): réveille tous ceux qui wait() - met le thread en attente, - permet aux autres threads d’exécuter 38