Title: Threads en Java (Livre Software engineering: chapitre 9)
1Threads en Java(Livre Software engineering
chapitre 9)
2Rappel
Thread
Thread
start()
extends Thread/ implement Runnable
extends Thread/ implement Runnable
Attributes
méthodeA()
méthodeA()
méthodeB()
méthodeB()
run()
run()
Attention !
3Réentrance
thread 1
thread 2 x
attribute
attribute attribute 1
x x1 attribute x
incrément perdu
4Singleton 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.
5Protection au moyen dun objet unique
thread 1 thread 2
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
6Protection au moyen de lobjet englobant
thread 1 thread 2
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.
7Wait - notify
thread 1
thread 2 1
wait ()
notify ()
2 3
8Wait - 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
9Wait 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
10Canal 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
11Canal 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
12Utilisation du canal
Channel channel new Channel() public void run
() // object avec thread
1 for (int i0ilt30i)
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)
13Les points importants receveur
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
Waiting
non
Donnéedisponible?
Il ne faut pas quun autre thread puisse
subtiliser la donnée après la décision.
oui
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.
Prendre la donnée
Les manipulations du buffer doivent être
protégées.
14Les points importants donneur
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!
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
Déposer une donnée
Notifier le receveur
15Sé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 (signalValue0) try
wait() catch
(InterruptedException ie) return
--signalValue
16Sémaphore (côté donneur)
Channel channel new Channel() class Channel
. . . int signalValue 0 public
synchronized void signal (Object obj)
signal notifyAll()
17Canal limité
class limitedChannel final int upperLimit
5 LinkedList llst new LinkedList()
public synchronized void put(Object obj)
while (llst.size() gt 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
18Canal 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
19Inversion de programmes1) basé sur des listeners
Listener
Observer partie de lapplication
Listener
Observer autre partie
20Inversion de programmes2) basé sur des
synchronisations
Observer read1 ou read2 partie de
lapplication read2 autre partie
Listener 1
Listener 2
Comme dans lexercice sur les factories de GUI
21Exercice
Listener
Objet avec thread ( objet actif)
Listener
Listener
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 )
22Analyse de programmes multithread
(livre Software Engineering, chapitre 9)
23Modélisation des threads
object M
T1
a
T3
synchronized
synchronized
a
T2
f
mw
mn
b
notify
wait
c
g
d
24Conditions 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.
25Une trace possible
lt a, a, f gt lt b, a, f gt lt c, a, g gt lt c, b, g
gt lt d, b, g gt
26Toutes les traces possibles
lta, a, fgt
ltb, a, fgt
lta, b, fgt
lta, a, ggt
ltc, a, ggt
ltb, b, fgt
lta, c, ggt
lta, b, ggt
ltb, a, ggt
ltd, a, ggt
ltc, b, ggt
ltb, c, ggt
lta, d, ggt
ltb, b, ggt
3
ltd, b, ggt
ltb, d, ggt
2
1
27Un exemple derreur
E/F
f
synchronized
synchronized
a
store
g
wait
h
notify
take
f
a
28Graphe des états
29Erreur
- On peut exécuter store depuis létat lta, f, Fgt
(cest-à-dire quon va écraser la donnée
précédente avant quelle ait été lue) - Dans létat lta, g, Fgt, une donnée est disponible,
mais le lecteur est bloqué
30Canal limité à une case
receive
send
a
f
while (empty)
while (not empty)
wait
wait
h
c
b
g
E/F
put
get
notify
notify
31Canal 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 ( )
32Graphe des états
33Exécution alternée
a
f
set
set
notifyAll
notifyAll
while (off )
while (off )
wait
wait
h
c
b
g
on/off
on/off
reset
reset
f
a
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.
34Graphe détats
35Ré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()
36Queue dobjets actifs(objet actif objet dont
run tourne sur un thread)
Réactive ce thread
37Attacher 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.
38Thread 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
39Exemple de connexion serveur-client
Browser
Serveur
html display_Manager - tireJetons(int)
servlet Manager - tireJetons(int) -
afficheJetons()
Client
topic testTopic
cmpbean Client String nom
class LoterieGUI - display TextArea - login
TextField - tireJeton TextField display(String)
listener
1 N
cmpbean Jeton int numero attente int etat
gagnant perdant
sbean ClientBean - login(String) -
tireJeton(int)
invokeLater
class Business - login(String) - tireJeton(int)
40Protection des threads en utilisant invokeLater
Server
41Module client
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)
)
42Classe 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)
. . .
43Finite State Machine
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)
44Exercice
- Créer une connexion qui gère une connexion entre
un client Java (rich client) et un serveur.
45Appels bloquants à TCP
Livre software Engineering, chapitre 3
46Lecture dun socket
import java.io. import java.net. byte
buffer new bytes1000 . . . ServerSocket
daemon new ServerSocket(8080) Socket
tcpSocket daemon.accept() InputStream tcpSin
tcpSocket.getInputStream() lengthRead
tcpSin.read(buffer, 0, bLength) if (lengthRead gt
0) String str new String(buffer, 0,
lengthRead) else System.out.println("Conn
ection closed")
47Appels non-bloquant au moyen dun thread
3 canaux 3 threads pas efficace !
Boucle sur la lecture de données
Canal limité get() put()
Application
Boucle sur la lecture de données
Canal limité get() put()
Boucle sur la lecture de données
Canal limité get() put()
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.
48Gestion de n canaux avec un thread (Java.nio)
import java.nio. import java.nio.channels. imp
ort java.nio.charset. ServerSocketChannel
serverSocketChannel SocketChannel
socketChannel SelectionKey selectionKey selecti
onKey createSelectionKey() while
(selectionKey.selector().select()gt0)
// infinite
loop Set readyKeys selectionKey.selector().s
electedKeys() 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()
49Appels 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
50Appels 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 lt 0)
// lautre extrémité a fermé le
socket socketChannel.close()
else if (lengthRead gt 0)
System.out.pritln( decode(buffer),
(someOject.toString())
51Fonctions 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-8859-1")
CharsetDecoder decoder charset.newDecoder()
CharBuffer charBuffer decoder.decode(byteBuffer)
return charBuffer.toString()