Sunteți pe pagina 1din 11

Laborator 9:

Fire de execuie

ntocmit de: Adina Neculai


ndrumtor: Asist. Drd. Gabriel Danciu
20 noiembrie 2011

I.
A.

NOIUNI TEORETICE
Ce este un fir de execuie?

nainte de a defini conceptul de fir de execuie sau thread, ne vom opri asupra conceptului
de multitasking. Acesta se refer la capacitatea unui computer de a executa mai multe programe
(task-uri, procese) n acelai timp. Avnd n vedere aceast noiune, putem defini conceptul de
multithreading care se refer la execuia mai multor secvene de cod n acelai timp, n cadrul
aceluiai program. O astfel de secven de cod se numete fir de execuie sau thread.
Un thread se execut n contextul unui program i nu poate fi tratat dect n cadrul unui
program. Exemplele prezentate pn acum au dispus de un sigur fir de execuie, adic de o singur
structur secvenial de instruciuni.

B.

Lucrul cu fire de execuie

Limbajul Java pune la dispoziia programatorului, in pachetul java.lang, dou clase i o interfa
pentru lucrul cu thread-uri:
clasa Thread: lucru cu thread-uri ca entiti separate;
clasa ThreadGroup: crearea unor grupuri de thread-uri n vederea tratrii acestora n mod
unitar;
interfaa Runnable: lucru cu thread-uri ca entiti separate.

1.

Crearea unui thread derivnd clasa Thread

Operaiile urmtoare reprezint numrul minim de pai ce trebuie ndeplinii pentru lucrul cu
un thread creat prin motenirea clasei Thread:
1. crearea unei clase obinuite care motenete clasa Thread.
class MyThread extends Thread{
}

2. suprascrierea metodei public void run() a clasei Thread n clasa derivat, MyThread. Instruciunile din aceast metod trebuie s implementeze ceea ce se dorete ca thread-ul s fac.
Aceasta poate apela alte metode, folosi alte clase i declara variabile ca orice metod.Metoda
run() este apelat atunci cnd se execut un thread.
Pentru a nelege mai bine se face o paralel cu metoda main. Aceasta care este apelat atunci
cnd se execut o aplicaie Java. Mai mult, atunci cnd JVM este pornit, se pornete o
dat cu ea un thread care apeleaz metoda main.
3. instanierea unui obiect thread prin intermediul operatorului new;
MyThread obThread = new MyThread();

4. pornirea thread-ului instaniat prin apelul metodei start() motenit din clasa Thread.
obThread.start();

Urmrii un exemplu de lucru cu thread-uri prin derivarea clasei Thread n seciunea II A.

2.

Crearea unui thread implementnd interfaa Runnable

Operaiile care trebuie ndeplinite pentru a putea crea un thread prin implementarea interfeei
Runnable sunt urmtorele:
1. crearea unei clase care s implementeze interfaa Runnable.
class MyRunnable implements Runnable {
}

2. clasa care implementeaz interfaa Runnable trebuie s suprascrie toate metodele definite
n aceasta, dar cum interfaa conine doar metoda run(), ea este singura metod ce trebuie
suprascris. Metoda run() implementeaz ceea ce se dorete ca thread-ul s fac.
3. se instaniaz un obiect al clasei create utiliznd operatorul new.
MyRunnable myRunnableObj = new MyRunnable();

4. se instaniaz un obiect al clasei Thread utiliznd un constructor ce are ca i parametru un


obiect de tipul clasei care implementeaz interfaa Runnable.
Thread thread = new Thread(myRunnableObj);

5. se pornete thread-ul.
thread.start();

Pentru o mai bun nelegere urmrii exemplul prezentat n seciunea II B.

3.

Clasa Thread vs interfaa Runnable

Clasa Thread definete o serie de metode ce pot fi suprascrise de clasa ce deriv din Thread.
Singura care trebuie suprascris obligatoriu este run(). ns, aceast condiie se impune i in cazul
clasei care implementeaz interfaa Runnable. Aadar, dac nu se dorete suprascrierea altor metode din Thread, atunci este mai bine s folosim a doua metod.
Mai mult, cum n Java nu este permis motenirea multipl, creare unui thread prin implementarea interfeei Runnable devine un avantaj pentru c acel thread poate s moteneasc funcionaliti
definite n alte clase Java.

C.

Controlul unui fir de execuie

Un thread se poate afla la un moment dat ntr-una din strile urmtoare: nou creat, n execuie,
blocat, terminat.
Clasa Thread conine o serie de metode ce controleaz execuia unui thread. Iat cteva dintre
cele mai importante:
Nume metod

Descriere

String getName()

se obine numele thread-ului

int getPriority()

se obine prioritatea thread-ului

boolean isAlive()

determin faptul c un thread mai este n execuie sau nu

void join()

foreaz un thread s atepte terminarea altuia

void run()

entry point pentru un thread

static void sleep(long millis) suspend execuia unui thread pentru millis milisecunde
void start()

ncepe execuia unui fir printr-un apel run()

void stop()

oprete execuia unui thread

Pentru mai multe informaii despre metodele clasei Thread consultai API-ul clasei.

D.

Prioriti

Aparent thread-urile se execut simultan, dar la un moment dat doar un singur thread are
acces la resursele de sistem. Fiecare thread obine o perioad de timp n care are acces la resurse,
accesul fcndu-se n mod organizat de ctre un planificator. Una dintre regulile pe care se bazeaz
planificatorul o reprezint mecanismul de prioriti.
Avnd n vedere cele spuse mai sus, fiecrui thread i se asociaz un nivel de prioritate (un numr
ntreg). Cu ct acest nivel este mai mare cu att thread-ul va avea prioritate mai mare la resurse.
Dac totui mai multe thread-uri au acelai nivel de prioritate, mecanismul de prioriti d dreptul
de execuie fiecruia printr-un algoritm circular.
Lucrul cu prioriti este exemplificat n seciunea II D.

E.

Sincronizarea firelor de execuie

Exist cazuri n care mai multe thread-uri acceseaz aceeai resurs aparent n acelai timp.
Pentru a evita astfel de situaii, care pot crea confuzie, limbajul Java ofer conceptul de monitor.
Acest lucru se realizeaz prin declararea unor metode, blocuri de cod ale unui obiect synchronized.
Modificatorul synchronized permite unui singur thread accesul, la un moment dat, la acele metode
sau blocuri de cod ale obiectului. Aadar, dac un thread apelez o metod synchronized a unui
obiect, un alt thread nu are acces la ea pn cnd primul thread nu a terminat-o de executat.
Exemplul este prezentat n seciunea II E.

II.

PREZENTAREA LUCRRII DE LABORATOR


A.

Crearea unui thread derivnd clasa Thread

Exemplul este destul de simplu i nu necesit explicaii suplimentare o dat ce au fost urmrii
paii din seciunea I B 1.
1 public c l a s s MyThread extends Thread {
2

p r i v a t e i n t countDown = 1 0 ;

3
4

public void run ( ) {

System . o u t . p r i n t l n ( " \ t b e g i n run method . . . " ) ;

while ( countDown >=0){

System . o u t . p r i n t l n ( " \ t \ t S t e p s l e t f t t o do : "+countDown ) ;

countDown;

10

System . o u t . p r i n t l n ( " \ t end run method ! " ) ;

11

12 }

1 public c l a s s DemoThread {
2
3

public s t a t i c void main ( S t r i n g [ ]

args ) {

System . o u t . p r i n t l n ( " b e g i n main . . . " ) ;

MyThread obThread = new MyThread ( ) ;

System . o u t . p r i n t l n ( " s t a r t t h e t h r e a d " ) ;

obThread . s t a r t ( ) ;

System . o u t . p r i n t l n ( " s t i l l i n main . . . " ) ;

10
11 }

Un singur lucru pare s fie curios: apariia mesajului still in main... imediat dup mesajul
start the thread. Acest lucru se ntmpl din cauza faptului c metoda main are propriul su fir
de execuie n care ruleaz. Prin apelul metodei start() a thread-ului se cere mainii virtuale Java
crearea i pornirea unui nou thread. Din acest moment JVM preia controlul execuiei programului
crend contextul necesar unui thread i n acest context se apeleaz metoda run(). Ca urmare se
iese imediat din metoda start().

B.

Crearea unui thread implementnd interfaa Runnable

Exemplul prezentat mai jos este puin mai complex n sensul c profitm de avantajele implementrii unei interfee, putnd totui moteni orice alt clas.
1 public c l a s s
2

Display {

public void p r i n t M e s s a g e ( S t r i n g m e s s a g e ) {

System . o u t . p r i n t l n ( m e s s a g e ) ;

5 }

Clasa MyRunnable motenete clasa Display, dar beneficiaz de proprietile unei clase de tip
thread prin implementarea interfeei Runnable. Unele dintre mbuntirile ce sunt aduse programului sunt mutarea instanierii thread-ului (se trimite ca parametru obiectul curent, deci un obiect
de tipul MyRunnable) i pornirea acestuia n constructorul clasei MyRunnable.
1 public c l a s s MyRunnable extends D i s p l a y implements Runnable {
2

p r i v a t e i n t countDown = 1 0 ;

p r i v a t e Thread t h r e a d ;

4
5

public MyRunnable ( ) {

t h r e a d = new Thread ( t h i s ) ;

System . o u t . p r i n t l n ( " s t a r t t h e t h r e a d " ) ;

thread . s t a r t () ;

10
11

public void run ( ) {

12

p r i n t M e s s a g e ( " \ t b e g i n run method . . . " ) ;

13

while ( countDown >= 0 ) {

14

p r i n t M e s s a g e ( " \ t \ t S t e p s l e t f t t o do : " + countDown ) ;

15

countDown;

16

17

p r i n t M e s s a g e ( " \ t end run method ! " ) ;

18

19 }

Clasa DemoRunnable instaniaz un obiect de tipul MyRunnable. Astfel se apeleaz constructorul unde se creeaz i se pornete thread-ul.
1 public c l a s s DemoRunnable {
2

public s t a t i c void main ( S t r i n g [ ]

args ) {

System . o u t . p r i n t l n ( " b e g i n main . . . " ) ;

MyRunnable myRunnableObj = new MyRunnable ( ) ;

System . o u t . p r i n t l n ( " s t i l l i n main . . . " ) ;

7 }

C.

Controlul unui fir de execuie

Exemplul urmtor prezint modul de utilizare al metodelor clasei Thread.


Clasa MyThread motenete clasa Thread i creeaz un constructor cu un parametru ce apeleaz
constructorul clasei de baz. Metoda run() este identic cu cea din exemplele anterioare.
1 public c l a s s MyThread extends Thread {
2

p r i v a t e i n t countDown = 5 ;

3
4

public MyThread ( S t r i n g name ) {

super ( name ) ;

7
8

public void run ( ) {

System . o u t . p r i n t l n ( " \ t b e g i n run method . . . " ) ;

10

while ( countDown

11

>=0){

System . o u t . p r i n t l n ( " \ t \ t S t e p s l e t f t t o do : "+countDown ) ;

12

countDown;

13

14

System . o u t . p r i n t l n ( " \ t end run method ! " ) ;

15

16 }

Clasa DemoThread creeaz dou thread-uri. Pe primul l pornete i l suspend pentru 4000
de milisecunde. Observai starea n care se afl thread-ul dup suspendarea temporar a acestuia
7

(apelul metodei isAlive()). Apoi, se pornete thread-ul al doilea i se blocheaz resursele acestuia
pn cnd se reia execuia lui (apelul metodei resume()). Observai starea thread-ului dup apelul
metodei suspend().
n cele din urm, se foreaz blocarea thread-ului principal pn cnd myThread2 ii termin
execuia (linia de cod 29).
1 public c l a s s DemoThread {
2

public s t a t i c void main ( S t r i n g [ ]

a r g s ) throws I n t e r r u p t e d E x c e p t i o n {

System . o u t . p r i n t l n ( " b e g i n main t h r e a d . . . " ) ;

MyThread myThread1 = new MyThread ( " t h r e a d 1 " ) ;

myThread1 . s t a r t ( ) ;

System . o u t . p r i n t l n ( myThread1 . getName ( ) ) ;

try {

myThread1 . s l e e p ( 4 0 0 0 ) ;

} catch ( I n t e r r u p t e d E x c e p t i o n e ) {

10

e . printStackTrace () ;

11

12

if

13

( myThread1 . i s A l i v e ( ) ) {
System . o u t . p r i n t l n ( myThread1 . getName ( )+" i s a l i v e ! " ) ;

14

} else {

15

System . o u t . p r i n t l n ( myThread1 . getName ( )+" i s t e r m i n a t e d ! " ) ;

16

17
18

MyThread myThread2 = new MyThread ( " t h r e a d 2 " ) ;

19

System . o u t . p r i n t l n ( myThread2 . getName ( ) ) ;

20

myThread2 . s t a r t ( ) ;

21

myThread1 . s u s p e n d ( ) ;

22

if

23

( myThread2 . i s A l i v e ( ) ) {
System . o u t . p r i n t l n ( myThread2 . getName ( )+" i s a l i v e ! " ) ;

24

} else {

25

System . o u t . p r i n t l n ( myThread2 . getName ( )+" i s t e r m i n a t e d ! " ) ;

26

27
28

System . o u t . p r i n t l n ( " b e f o r e main t h r e a d s l e e p s " ) ;

29

Thread . s l e e p ( 2 0 0 0 ) ;

30

System . o u t . p r i n t l n ( " a f t e r main t h r e a d h a s s l e p t " ) ;

31
32

myThread2 . s l e e p ( 2 0 0 0 ) ;

33

myThread2 . resume ( ) ;

34

try {

35

myThread2 . j o i n ( ) ;

36

} catch ( I n t e r r u p t e d E x c e p t i o n e ) {

37

e . printStackTrace () ;

38

39

myThread2 . s l e e p ( 1 0 0 0 ) ;

40
41

System . o u t . p r i n t l n ( " end main t h r e a d ! ! ! " ) ;


}

42 }

D.

Prioriti

Clasa PriorityThread implementeaz interfaa Runnable i are un constructor cu un parametru


ce seteaz nivelul de prioritate al thread-ului i care instaniaz un obiect de tip thread, prezent
ca atribut al clasei. Metoda run() apeleaz metoda toString() a clasei Thread ct timp atributul
countDown este mai mare ca 0.
1 public c l a s s
2

P r i o r i t y T h r e a d implements Runnable {

p r i v a t e i n t countDown = 5 ;

private int

public Thread t h r e a d ;

priority ;

5
6

public P r i o r i t y T h r e a d ( i n t

priority ) {

this . p r i o r i t y = p r i o r i t y ;

t h r e a d = new Thread ( t h i s ) ;

10
11

public void run ( ) {

12

thread . s e t P r i o r i t y ( p r i o r i t y ) ;

13

System . o u t . p r i n t l n ( " \ t b e g i n run method . . . " ) ;

14

while ( countDown

15

>=0){

System . o u t . p r i n t l n ( t h r e a d . t o S t r i n g ( )+" countDown : "+countDown ) ;

16

countDown;

17

18

System . o u t . p r i n t l n ( " \ t end run method ! " ) ;

19

20 }

Clasa DemoPriority creeaz dou obiecte de tipul PriorityThread cu parametri declarai ca


i constante n clasa Thread. Se pornete execuia acestora i thread-ul principal este obligat s
atepte terminarea execuiei celor dou thread-uri anterioare nainte de a deveni inactiv.
Observai ordinea n care se pornesc thread-urile i ordinea n care se execut.
1 public c l a s s D e m o P r i o r i t y {
2

public s t a t i c void main ( S t r i n g [ ]

args ) {

System . o u t . p r i n t l n ( " b e g i n main t h r e a d . . . " ) ;

P r i o r i t y T h r e a d t h r e ad M i n = new P r i o r i t y T h r e a d ( Thread . MIN_PRIORITY) ;

P r i o r i t y T h r e a d threadMax = new P r i o r i t y T h r e a d ( Thread . MAX_PRIORITY) ;

threadMin . t h r e a d . s t a r t ( ) ;

threadMax . t h r e a d . s t a r t ( ) ;

try {

threadMax . t h r e a d . j o i n ( ) ;

10

threadMin . t h r e a d . j o i n ( ) ;

11

} catch ( I n t e r r u p t e d E x c e p t i o n e ) {

12

System . o u t . p r i n t l n ( " i n t e r r u p t e d e x c e p t i o n " ) ;

13

14
15

System . o u t . p r i n t l n ( " end main t h r e a d ! ! ! " ) ;


}

16 }

E.

Sincronizarea firelor de execuie

Clasa MySynchronized are un constructor cu doi parametri. Unul este de tip String i reprezint
numele thread-ului, iar cel de-al doilea este un numr ntreg. Constructorul este cel care instaniaz
thread-ul i tot el este cel care l pornete.
Observai cele dou metode care folosesc modificatorul synchronized. Prima metod l folosete
ca modificator al funciei, iar ce-a de-a doua metod, cea ntre comentarii, l folosete ca i bloc.
Important de reinut este c n varianta bloc synchronized se aplic doar pe obiecte.
1 public c l a s s MySynchronized implements Runnable {
2

private int count ;

p r i v a t e Thread t h r e a d ;

4
5

public MySynchronized ( S t r i n g name ,

this . count

t h r e a d = new Thread ( t h i s , name ) ;

8
9

int count ) {

= count ;

thread . s t a r t () ;
}

10
11

public synchronized i n t add ( ) {

12

c o u n t ++;

13

try {

14

Thread . s l e e p ( 1 0 0 0 ) ;

15

} catch ( I n t e r r u p t e d E x c e p t i o n e ) {

16

System . o u t . p r i n t l n ( " main t h r e a d i n t e r r u p t e d " ) ;

17

18

++c o u n t ;

19
20

return c o u n t ;
}

21
22

/ p u b l i c

23

i n t add ( ) {

synchronized

24

c o u n t ++;

25

try {

26

Thread . s l e e p ( 1 0 0 0 ) ;

27

} catch ( InterruptedException e ) {

28

System . o u t . p r i n t l n ( " main t h r e a d

29

30

++c o u n t ;

31

interrupted ") ;

r e t u r n count ;

32
33

( thread ) {

}
} /

34
35

public void run ( ) {

36

System . o u t . p r i n t l n ( t h r e a d . getName ( ) + " s t a r t i n g . " ) ;

37

System . o u t . p r i n t l n ( " \ t t h e numer o f "+t h r e a d . getName ( )+" i s : "+add ( ) ) ;

38
39

System . o u t . p r i n t l n ( t h r e a d . getName ( ) + " t e r m i n a t i n g . " ) ;


}

40 }

Clasa DemoSynchronized creeaz dou obiecte de tipul MySynchronized.


1 public c l a s s DemoSynchronized {

10

public s t a t i c void main ( S t r i n g [ ]

args ) {

System . o u t . p r i n t l n ( " b e g i n main t h r e a d . . . " ) ;

MySynchronized t h r e a d 1 = new MySynchronized ( " t h r e a d 1 " , 1 ) ;

MySynchronized t h r e a d 2 M y S y n c r o n i z e d = new MySynchronized ( " t h r e a d 2 " , 2 ) ;

System . o u t . p r i n t l n ( " b e g i n main t h r e a d . . . " ) ;

8 }

III.

TEM

1. Realizai un program care creeaz cel puin dou fire de execuie ce calculeaz produsul
elementelor aceluiai vector. Elementele vectorului se vor citi din fiierul in.txt, iar rezultatul
se va afia ntr-un alt fiier, out.txt. Cerine de implementare:
pentru calculul produsului folosii synchronized (ori modificatorul de acces ori ca bloc);
pentru implementarea thread-urilor putei folosi oricare dintre cele dou metode prezentate n laborator;
att pentru lucrul cu fiiere ct i pentru lucrul cu thread-uri se vor folosi mecanisme
de tratare a excepiilor.

11