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

Post on 04-Apr-2015

118 Views

Category:

Documents

2 Downloads

Preview:

Click to see full reader

TRANSCRIPT

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

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 . . . }}

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

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

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)…

8

Explication de thread

Séquence d’actions

• Bien ordonnée en parallèle

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

10

Exemple1: Utilisation du Thread

• Lancer 2 Threadspublic class TwoThreadsTest {

public static void main (String[] args) {

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

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

}

}

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

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

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

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

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 }}

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

17

Détecter l’état d’un Thread

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

18

Synchronisation

Accès conflictuels:écrire lire

(put - producer) (get -consumer)

+2 -100X

-20*1.02

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) {}

}…

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

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

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

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

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

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

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;

}…

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

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

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

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

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

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

}

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

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

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

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

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;

}}

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

top related