1 ift1025 – programmation 2 multi-thread jian-yun nie

38
1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

Upload: gautier-saunier

Post on 04-Apr-2015

118 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

1

IFT1025 – Programmation 2

Multi-Thread

Jian-Yun Nie

Page 2: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

2

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

Page 3: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

3

Interface Runnable

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

• Implantation:public class MyRunnable implements Runnable{ public void run() { // Task statements go here . . . }}

Page 4: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

4

Créer un threadUn Thread est une classe qui implante Runnable

1. Créer une sous-classe de Thread (doit aussi implanter run() )

class PrimeThread extends Thread { long minPrime; PrimeThread(long minPrime) { this.minPrime = minPrime; } public void run() { // compute primes larger than minPrime . . . } }

Utilisation: PrimeThread p = new PrimeThread(143); p.start();

Page 5: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

5

Créer un thread

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

Runnable r = new MyRunnable();

Thread t = new Thread(r);

t.start();

Page 7: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

7

Classe Thread

• Méthodes:static int activeCount(): nb. de threads de ce groupevoid 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)…

Page 8: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

8

Explication de thread

Séquence d’actions

• Bien ordonnée en parallèle

Page 9: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

9

Exemple1: Définition de Thread• Créer une sous-classe de Thread:

public class SimpleThread extends Thread { public SimpleThread(String str) { super(str); }

public void run() { for (int i = 0; i < 10; i++) { System.out.format("%d %s%n", i, getName()); try { sleep((long)(Math.random() * 1000)); } catch (InterruptedException e) {} } System.out.format("DONE! %s%n", getName()); }}

Thread avec un nom

Méthode run():

10 fois: Afficher le nom du Thread et sleep un temps aléatoire

Page 10: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

10

Exemple1: Utilisation du Thread

• Lancer 2 Threadspublic class TwoThreadsTest {

public static void main (String[] args) {

new SimpleThread("Jamaica").start();

new SimpleThread("Fiji").start();

}

}

Page 11: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

11

Différence avec un appel à run()

public class TwoThreadsTest { public static void main (String[] args) { new SimpleThread("Jamaica").run(); new SimpleThread("Fiji").run(); }}

0 Jamaica1 Jamaica2 Jamaica3 Jamaica4 Jamaica5 Jamaica6 Jamaica7 Jamaica8 Jamaica9 JamaicaDONE! Jamaica0 Fiji1 Fiji2 Fiji3 Fiji4 Fiji5 Fiji6 Fiji7 Fiji8 Fiji9 FijiDONE! Fiji

Page 12: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

12

Exemple 2: Clockimport java.awt.*;import java.util.*;import java.applet.*;import java.text.*;

public class Clock extends java.applet.Applet implements Runnable { private volatile Thread clockThread = null; DateFormat formatter; //Formats the date displayed String lastdate; //String to hold date displayed Date currentDate; //Used to get date to display Color numberColor; //Color of numbers Font clockFaceFont; Locale locale;

public void init() { setBackground(Color.white); numberColor = Color.red; locale = Locale.getDefault(); formatter = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.MEDIUM, locale); currentDate = new Date(); lastdate = formatter.format(currentDate); clockFaceFont = new Font("Sans-Serif", Font.PLAIN, 14); resize(275, 25); }

public void start() { if (clockThread == null) {

clockThread = new Thread(this, "Clock"); clockThread.start(); } }

public void run() { Thread myThread = Thread.currentThread(); while (clockThread == myThread) { repaint(); try { Thread.sleep(1000); } catch (InterruptedException e){ } } }

public void paint(Graphics g) { String today; currentDate = new Date(); formatter = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.MEDIUM, locale); today = formatter.format(currentDate); g.setFont(clockFaceFont);

//Erase and redraw g.setColor(getBackground()); g.drawString(lastdate, 0, 12);

g.setColor(numberColor); g.drawString(today, 0, 12); lastdate = today; currentDate = null; }

public void stop() { clockThread = null; }}

start de Applet

start de Thread – run()

stop: si la fenêtre ferme

Temps courant

Tant que non-fini, reffiche toute les secondes

Page 13: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

13

Déclarer Thread avec Thread ou Runnable?

1. Créer une sous-classe de Thread2. 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

Page 14: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

14

États d’un Thead

• Création et lancement:public void start() { if (clockThread == null) { clockThread = new Thread(this, "Clock"); clockThread.start(); }}

• Entrer dans Runnable• Not Runnable: sleep(), E/S• Dead: terminaison: Fermer Applet -> exécuter stop()

public void stop() { //applet's stop method clockThread = null;}

Page 15: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

15

Terminer un Thread

Schéma typique:

public void run(){ try { for (int i = 1; i <= REPETITIONS; i++) { // Do work } } catch (InterruptedException exception) { // Clean up }}

Page 16: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

16

Exemplepublic class MyRunnable implements Runnable{ public void run() { try { System.out.println(1); Thread.sleep(1000); System.out.println(2); } catch (InterruptedException exception) { System.out.println(3); } System.out.println(4); }}• Sortie?

1, 3, 4

Page 17: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

17

Détecter l’état d’un Thread

• Thread.getState():– NEW – RUNNABLE – BLOCKED – WAITING – TIMED_WAITING – TERMINATED

Page 18: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

18

Synchronisation

Accès conflictuels:écrire lire

(put - producer) (get -consumer)

+2 -100X

-20*1.02

Page 19: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

19

Exemple: Accéder au même BankAcountpublic class DepositRunnable

implements Runnable{public void run(){ try { for (int i = 1; i <= count; i++) { account.deposit(amount); Thread.sleep(DELAY); } } catch (InterruptedException

exception) { }}…

public class WithdrawRunnable implements Runnable

{ public void run(){

try {

for (int i = 1; i <= count; i++) {

account.withdraw(amount);Thread.sleep(DELAY);

}}catch (InterruptedException exception) {}

}…

Page 20: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

20

Depositing 100.0, new balance is 100.0

Withdrawing 100.0, new balance is 0.0

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

new DepositRunnable().start();

new WithdrawRunnable().start();

Page 21: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

21

Synchronisation: Solution 1• Bloquer la ressource durant un traitement:

public class BankAccount{ public BankAccount() { balanceChangeLock = new ReentrantLock(); . . . } . . . private Lock balanceChangeLock;}

• Utilisation typique:– balanceChangeLock.lock();– Code that manipulates the shared resource– balanceChangeLock.unlock();

Page 22: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

22

Utilisation typiquepublic void deposit(double amount){ balanceChangeLock.lock(); try { System.out.print("Depositing " + amount); double newBalance = balance + amount; System.out.println(", new balance is " + newBalance); balance = newBalance; } finally { balanceChangeLock.unlock(); }}

Toujours dans BankAccount

Finally: Pour que ça fonctionne même si une exception est lancée

Page 23: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

23

Interface Lock

• void lock(): bloquer la ressource• Condition newCondition(): associer une

condition (plus tard)• void unlock(): débloquer

Les classes qui implante l’interface Lock:ReentrantLock, ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock

Page 24: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

24

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(); }

Page 25: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

25

ReentrantLock• Une classe qui implante Lock• Plus de méthodes que celles exigées dans Lock

class X { private final ReentrantLock lock = new ReentrantLock(); // ...

public void m() { lock.lock(); // block until condition holds try { // ... method body }

finally {

lock.unlock() } } }

Page 26: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

26

Synchronisation: Solution 2synchronized: réalise block, try [bloc], finally {unlock}

public class BankAccount{

public synchronized void deposit(double amount){

System.out.print("Depositing " + amount);double newBalance = balance + amount;System.out.println(", new balance is " + newBalance);balance = newBalance;

}

public synchronized void withdraw(double amount){

System.out.print("Withdrawing " + amount);double newBalance = balance - amount;System.out.println(", new balance is " + newBalance);balance = newBalance;

}…

Page 27: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

27

Problème de Deadlock

• 2 ou plus Threads attendent qu’un autre thread débloque une ressource nécessaire

Possède A

Demande B

Possède C

Demande A

Possède B

Demande C

Page 28: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

28

Une solution à Deadlock (façon 1)

• Objet Condition associé à un Lock

public class BankAccount{ public BankAccount() //Constructeur { balanceChangeLock = new ReentrantLock(); sufficientFundsCondition = balanceChangeLock.newCondition(); . . . } . . . private Lock balanceChangeLock; private Condition sufficientFundsCondition;}

Page 29: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

29

Une solution à Deadlock

• Un retrait attend la condition nécessaire

public void withdraw(double amount){ balanceChangeLock.lock(); try { while (balance < amount) sufficientFundsCondition.await(); . . . } finally { balanceChangeLock.unlock(); }}

Page 30: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

30

Effets de await()

sufficientFundsCondition.await();

• Attendre la ressource nécessaire (suffisamment d’argent)

• Relâche l’objet bloqué en attendant (BankAccount)– Permet aux autres threads d’exécuter

• L’attente se réveille quand il reçoit un signal – signalAll()

Page 31: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

31

Une solution à Deadlock

• Un retrait attend la condition nécessaire

public void withdraw(double amount){ balanceChangeLock.lock(); try { while (balance < amount) sufficientFundsCondition.await(); . . . // faire le retrait } finally { balanceChangeLock.unlock(); }}

Le thread attend, relâche l’objet BankAcount, attend d’être signalé (ou interrompu)

Quand il est signalé, on doit tester encore la condition balance < amount

Page 32: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

32

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

possiblement changée

public void deposit(double amount){

balanceChangeLock.lock();try{

System.out.print("Depositing " + amount);double newBalance = balance + amount;System.out.println(", new balance is " + newBalance);balance = newBalance;sufficientFundsCondition.signalAll();

}finally{

balanceChange.unlock();}

}

Page 33: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

33

Condition

• Construction à partir d’un Lock:– Lock.newCondition()

• Méthodes de Condition:– void await(): attend d’être signalé ou

interrompu– void signal(): réveille un thread qui attend– void signalAll(): réveille tous les threads qui

attendent

Page 34: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

34

Résuméclass Ressource{ Lock l;

Condition c = l.newCondition();

public void methode1 //consumer{ l.lock();

try { while (…) c.await(); … }finally {l.unlock();}

}

public void methode2 //producer{

l.lock();try { …, signalAll(); }finally {l.unclock();

}…}

Méthode qui attend une condition

Méthode qui peut satisfaire ne condition d’un autre thread

Page 35: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

35

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

Page 36: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

36

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 notifyAll(): signale à tous les Threads

Page 37: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

37

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;

}}

Page 38: 1 IFT1025 – Programmation 2 Multi-Thread Jian-Yun Nie

38

Solution à Deadlock (façon 3)public synchronized int get() { while (available == false) { try { //Wait for Producer to put value. wait(); } catch (InterruptedException e) { } } available = false; //Notify Producer that value has been

retrieved. notifyAll(); return contents;}

public synchronized void put(int value) { while (available == true) { try { //Wait for Consumer to get value. wait(); } catch (InterruptedException e) { } } contents = value; available = true; //Notify Consumer that value has been

set. notifyAll();}

Tant que la condition n’est pas vraie, wait():

- met le thread en attente,

- permet aux autres threads d’exécuter

notifyAll(): réveille tous ceux qui wait()