La présentation est en train de télécharger. S'il vous plaît, attendez

La présentation est en train de télécharger. S'il vous plaît, attendez

Threads en Java ( Livre Software engineering: chapitre 9)

Présentations similaires


Présentation au sujet: "Threads en Java ( Livre Software engineering: chapitre 9)"— Transcription de la présentation:

1 Threads en Java ( Livre Software engineering: chapitre 9)

2 Thread Rappel extends Thread/ implement Runnable méthodeA() méthodeB() run() Thread extends Thread/ implement Runnable Attributes méthodeA() méthodeB() run() start() Attention !

3 Réentrance thread 1 thread 2 x = attribute attribute = attribute + 1 x = x+1 attribute = x incrément perdu

4 Singleton partagé par deux threads Lutilisation du singleton par deux threads proposée au début du cours était une erreur. Bien quil utilisait id++, une instruction qui paraît atomique, pour créer différents ids, nous avons vu sur une station dans laquelle les hyperthreads étaient actifs, que les deux threads obtenaient la même valeur !!! Cet id était incrémenté, mais une seule fois, après le passage des deux threads. Le problème vient de la JVM, qui prend les variables dans son ALU pour les manipuler ! Il faut donc utiliser les protections indiquées dans les prochains slides.

5 Protection au moyen dun objet unique class Xxx { Object o = new Object(); public void methodeB() { synchronized (o) { // one thread at a time attribute = attribute + 1; } La méthode run() pourrait être une méthode de la classe Xxxx thread 1 thread 2

6 Protection au moyen de lobjet englobant class Xxx { public synchronized void methodeB() { attribute = attribute + 1; } // lobjet unique de protection est lobjet qui contient methodeB(). Il doit être instancié. Pas daccès static. thread 1 thread 2

7 Wait - notify thread 1 thread 2 1 wait () notify () 2 3

8 Wait - notifyAll thread 1 thread 2 1 wait () notifyAll () 2 1 wait() 3 3 notify ne redémarre quun thread, choisi on ne sait pas comment

9 Wait et notify doivent être placés dans un bloc synchronized (Sémaphore sans mémoire) class Sem {public synchronized void kick () { notify(); } public synchronized void stop () { try { wait(); } catch (InterruptedException ie) {} } // ou utiliser un autre objet commun

10 Canal: input (=Sémaphore à mémoire) Channel channel = new Channel(); class Channel { LinkedList list = new LinkedList(); public synchronized void put (Object obj) { list.addLast(obj); notifyAll(); } Pas dinterférences de plusieurs threads dans la méthode synchronisée Ne peuvent pas être séparées

11 Canal: output Channel channel = new Channel(); class Channel {... public synchronized Object get () { while (list.size()==0) try { wait(); } catch (InterruptedException ie){} return list.remove(0); // get the int stored in Integer } Ne peuvent pas être séparées

12 Utilisation du canal Channel channel = new Channel(); public void run () { // object avec thread 1 for (int i=0;i<30;i++) { System.out.println("T1"+i); channel.put(new Integer(i)); } public void run () { // object avec thread 2 for (;;) { int j = ((Integer)channel.get()).intValue(); System.out.println(" T2 "+j); }

13 Les points importants: receveur Waiting non oui Donnée disponible? Prendre la donnée Il ne faut pas quun autre thread puisse subtiliser la donnée après la décision. Il ne faut pas quun autre thread puisse déposer une donnée et notifier cet objet-ci entre le moment où il teste et le moment où il dans son état Waiting. Le signal de notification serait perdu sinon. Les manipulations du buffer doivent être protégées. Le wait doit placé être dans une bou- cle, car le donateur peut démarrer plusieurs threads. Cet objet-ci risque dêtre réveillé alors quil ny a plus de données

14 Les points importants: donneur Notifier le receveur Déposer une donnée Le donateur ne doit pas sexécuter si le receveur est dans une des zones de protection. Il doit déposer la donnée avant de notifier le receveur Le receveur ne doit pas pouvoir sexécuter entre les deux actions. Sil ny a pas de receveur en attente, la notification est perdue, mais ce nest pas grave!

15 Sémaphore à compteur (côté receveur) Plutôt que de stocker des messages, on peut incrémenter une variable qui compte un nombre de messages virtuels Channel channel = new Channel(); class Channel { int signalValue = 0;... public synchronized Object awaitSignal () { while (signalValue==0) try { wait(); } catch (InterruptedException ie){} return --signal Value ; }

16 Sémaphore (côté donneur) Channel channel = new Channel(); class Channel {... int signalValue = 0; public synchronized void signal (Object obj) { ++signal; notifyAll(); }

17 Canal limité class limitedChannel { final int upperLimit = 5; LinkedList llst = new LinkedList(); public synchronized void put(Object obj) { while (llst.size() >= upperLimi) // wait if full try { wait(); } catch (InterruptedException ie){} llst.addLast(obj); if (llst.size() == 1) notifyAll(); } } // notifyAll réactive tous les threads en attente. Sil en vient // après, ils ne seront pas bloqués avant que le canal soit vide

18 Canal limité... public synchronized Object get() { while (llst.size() == 0)// wait if list empty try { wait(); } catch (InterruptedException ie{} Object obj = llst.remove(0); if (llst.size()==(upperLimit-1))// maybe an object was notifyAll();// waiting to put data return obj;// it can do it now } } // symmétrique du précédent transparent

19 Inversion de programmes 1) basé sur des listeners Listener Observer partie de lapplication Listener Observer autre partie

20 Inversion de programmes 2) basé sur des synchronisations Listener 1 Observer read1 ou read2 partie de lapplication read2 autre partie Listener 2 Comme dans lexercice sur les factories de GUI

21 Exercice Listener Objet avec thread (= objet actif) Ecrire le code qui permet à lobjet actif de lire le premier dun ensemble de listeners qui reçoit un signal en effectuant lappel await ( new Object [ ] {listener1, listener3} );

22 Analyse de programmes multithread (livre Software Engineering, chapitre 9)

23 Modélisation des threads object M wait a b c d T1 T2 T3 a notify synchronized mw g f mn

24 Conditions de transitions Un ou deux threads sont dans la position b et un thread est en f. Dans ces conditions, un des threads en b peut passer proceed en c, en quel cas le thread en f passe en g simultanément. un thread en f peut passer en g même sil ny a pas de thread en b. un thread en b est bloqué jusquà ce que le notify soit exécuté. Chaque autre transition peut être exécutée chaque fois quun thread est dans létat de la transition.

25 Une trace possible

26 Toutes les traces possibles 1 3 2

27 Un exemple derreur a f a wait notify synchronized g h f E/F store take

28 Graphe des états take store a, f, E a, g, E a, f, F a, h, F a, g, F initial state

29 Erreur On peut exécuter store depuis létat (cest-à-dire quon va écraser la donnée précédente avant quelle ait été lue) Dans létat, une donnée est disponible, mais le lecteur est bloqué

30 Canal limité à une case wait a b c notify while (not empty) wait while (empty) g h f get put E/F send receive

31 Canal limité à une case synchronized int receive () { while (empty) wait ( ) ; x = get ( ); notify ( ) ; } int x; synchronized void send (int x) { while (not empty) wait ( ) ; put (x); notify ( ); }

32 Graphe des états a, f, Ea, f, F a, g, Eb, f, F c, f, Ea, h, F c, g, Eb, h, F put get

33 Exécution alternée wait a b c a notifyAll while (off ) wait while (off ) g f h f reset set on/off reset on/off set Les threads se passent un jeton. Le thread qui possède le jeton est en exécution jusquà ce quil le retourne au partnaire. Il y a rendez-vous des deux threads au moment du passage du jeton.

34 Graphe détats a, off, g, offb, off, h, on c, on, g, offb, off, f, off

35 Réactiver un thread donné class Trigger { boolean triggered = false; public Object message; public synchronized void block() { while (!triggered) try { wait(); } catch (InterruptedException ie) { } triggered = false; } public synchronized void unblock() { triggered = true; notify(); } Un objet de classe Trigger mémorise la référence dun thread. On peut mettre cette classe dans une queue et ainsi réactiver le premier ou nimporte quel thread dune queue, contrairement à un simple notify()

36 Queue dobjets actifs (objet actif = objet dont run tourne sur un thread) list active object Trigger wait notify scheduler active object Trigger wait notify active object Trigger wait notify Réactive ce thread

37 Attacher le Trigger au thread class Trigger { private static ThreadLocal currentTrigger = new ThreadLocal() { protected synchronized Object initialValue() { return new Trigger(); } }; public static Trigger get(){ // get the trigger of the thread return (Trigger)currentTrigger.get(); // running currently } boolean triggered = false; public Object message; // to pass messages public synchronized void block() {... transparent précédent... } public synchronized void unblock() {... transparent précédent... } } En plaçant un thread dans un objet ThreadLocal, on peut le bloquer depuis nimporte quelle méthode, car elles peuvent toutes retrouver le trigger.

38 Thread système / utilisateur Le GUI est exécuté sur un thread appartenant au système. Le listener du réseau (inputchannel) est exécuté sur un thread de lutilisateur. On na donc pas le droit dappeler la plupart des fonctions du GUI depuis la méthode contenue dans le listener du réseau. Il faut utiliser la fonction invokeLater

39 Exemple de connexion serveur-client Browser Serveur cmpbean: Client String nom cmpbean: Jeton int numero attente int etat gagnant perdant 1N1N html: display_Manager - tireJetons(int) servlet: Manager - tireJetons(int) - afficheJetons() Java bean: LotteryData - constantes générales - client Client topic: testTopic listener: class: LoterieGUI - display: TextArea - login: TextField - tireJeton: TextField display(String) class: Business - login(String) - tireJeton(int) invokeLater sbean: ClientBean - login(String) - tireJeton(int)

40 Server Java client GUI Listeners actionPerformed() { } Business layer FSM () { } Message Listener onMessage () { } GUI setUsername () getUsername () setPosition () setError () topic invokeLater Protection des threads en utilisant invokeLater

41 jclient MyClient { package myPackage; inputchannel inputName (topic, "MDBTopic") { String s = ((TextMessage)msg).getText()); java.awt.EventQueue.invokeLater( new Runnable() { public void run() { fsmBusiness.transition(reseau, s); } } ); } } Module client

42 Classe en WebLang class Business { package ppp; outputchannel ch (topic, testTopic); access Remote; public Business(LoterieGUI gui) { this.gui = gui; } public void transition(String source, String param) {... }

43 public void transition(String source, String param) { try { switch (state) { case 0: if (source != "username") return; game = gameHome().findByName(gui.getGameName());... state = 1; break; case 1: if (source != "nextmove") return; state = 2; break; case 2: if (source != "done") return; game.moveTerminated(); state = 1; } } catch (Exception e) { } } Finite State Machine

44 Exercice: Créer une connexion qui gère une connexion entre un client Java (rich client) et un serveur.

45 Appels bloquants à TCP data socket daemon socket data socket Client 1 Client 2 Server Livre software Engineering, chapitre 3

46 Lecture dun socket import java.io.*; import java.net.*; byte [] buffer = new bytes{1000];... ServerSocket daemon = new ServerSocket(8080); Socket tcpSocket = daemon.accept(); InputStream tcpSin = tcpSocket.getInputStream(); lengthRead = tcpSin.read(buffer, 0, bLength); if (lengthRead > 0) { String str = new String(buffer, 0, lengthRead); } else { System.out.println("Connection closed"); }

47 Appels non-bloquant au moyen dun thread Application Canal limité get() put() Boucle sur la lecture de données Ne pas utiliser directement les wait et notify, il est très difficile déviter toutes les erreurs, car elles peuvent être très subtiles. Canal limité get() put() Boucle sur la lecture de données Canal limité get() put() Boucle sur la lecture de données 3 canaux = 3 threads pas efficace !

48 import java.nio.*; import java.nio.channels.*; import java.nio.charset.*; ServerSocketChannel serverSocketChannel; SocketChannel socketChannel; SelectionKey selectionKey; selectionKey = createSelectionKey(); while (selectionKey.selector().select()>0) { // infinite loop Set readyKeys = selectionKey.selector().selectedKeys(); Iterator it = readyKeys.iterator(); while (it.hasNext()) { // loop over the most recent keys try { selectionKey = (SelectionKey) it.next(); if (selectionKey.isAcceptable()) { // a new client has produced a new socket... } else if (selectionKey.isReadable()) { // a data socket has received data... } catch (IOException e) { socketChannel.close(); // something has closed the socket it.remove(); } Gestion de n canaux avec un thread (Java.nio)

49 Appels non bloquants (Java.nio) // un client a produit un nouveau socket, prendre le socket, lenregistrer et // optionnellement y attacher un objet auxiliaire serverSocketChannel = (ServerSocketChannel) selectionKey.channel(); socketChannel = serverSocketChannel.accept(); socketChannel.configureBlocking(false); SelectionKey socketChannelKey = socketChannel.register(selectionKey.selector(),SelectionKey.OP_READ); socketChannelKey.attach(someObject); // après enregistrement, larrivée de données sera détecté dans la key

50 Appels non bloquants (Java.nio) // un data socket a reçu des données socketChannel = (SocketChannel) selectionKey.channel(); int lengthRead = 0; buffer = ByteBuffer.wrap(bBuffer); lengthRead = socketChannel.read(buffer); buffer.flip(); if (lengthRead < 0) { // lautre extrémité a fermé le socket socketChannel.close(); } else if (lengthRead > 0) { System.out.pritln( decode(buffer), (someOject.toString()); }

51 Fonctions auxiliaires public SelectionKey createSelectionKey() throws IOException { // voir le livre ou son site Web } public String decode(ByteBuffer byteBuffer) throws CharacterCodingException { Charset charset = Charset.forName("iso "); CharsetDecoder decoder = charset.newDecoder(); CharBuffer charBuffer = decoder.decode(byteBuffer); return charBuffer.toString(); }


Télécharger ppt "Threads en Java ( Livre Software engineering: chapitre 9)"

Présentations similaires


Annonces Google