0% au considerat acest document util (0 voturi)
48 vizualizări

Programare Java Curs 4 2020

Încărcat de

ZighiStone
Drepturi de autor
© © All Rights Reserved
Formate disponibile
Descărcați ca PDF, TXT sau citiți online pe Scribd
0% au considerat acest document util (0 voturi)
48 vizualizări

Programare Java Curs 4 2020

Încărcat de

ZighiStone
Drepturi de autor
© © All Rights Reserved
Formate disponibile
Descărcați ca PDF, TXT sau citiți online pe Scribd
Sunteți pe pagina 1/ 41

UNIVERSITATEA TEHNICĂ “GHEORGHE ASACHI” DIN IAŞI

FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

Programare Java

III. Fire de execuție în Java

2020
Fire de execuție în Java
Cuprins
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

1. Introducere

2. Crearea unui fir de execuție


UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

3. Stările unui fir de execuție

4. Crearea și lansarea a două fire de execuție

5. Prioritatea firelor de execuție

6. Sincronizarea firelor de execuție

7. Întrebări
Fire de execuție în Java
1. Introducere
❖ Conceptul de multitasking
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

- se referă la capacitatea unui sistem de a executa mai multe programe în


același timp
- Un system multitasking poate realiza concomitent mai multe sarcini prin
partajarea resurselor de calcul, cum ar fi CPUs, memoria principală, canale I/O
- nu implică neapărat un sistem multiprocesor: SO conține un mecanism de
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

management al sarcinilor. Astfel, SO alocă fiecărui task o cuantă de timp


pentru execuție, cuantă în care respectivul task este executat de procesor.
Accesul task-urilor la procesor se face periodic. Task-urile care nu se execută își
așteaptă rândul într-o coadă de așteptare. Ordinea în coadă este stabilită pe
baza unui mecanism de priorități.
- rezultă o aparentă execuție simultană a mai multor programe
Fire de execuție în Java
1. Introducere
❖ Conceptul de multithreading (fire multiple de execuție)
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

- Java suportă atât operații pe fir unic de execuție (single-thread), cât și pe fire
multiple de execuție (multi-thread) .
- Un program single-thread are un singur punct de intrare ( metoda main() ) și un
singur punct de ieșire.
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

- Un program multi-thread are un punct inițial de intrare ( metoda main() ), urmat de


mai multe puncte de intrare și de ieșire, care rulează concomitent cu main().
- Un fir de execuție (thread) este o succesiune secvențială de instrucțiuni care se
execută în cadrul unui proces (program).
- In fig de mai jos: un program cu 3 fire de execuție ce rulează pe un singur CPU.
Fire de execuție în Java
1. Introducere
❖ Conceptul de multithreading (fire multiple de execuție)
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

- reprezintă capacitatea unui program de a executa mai multe secvențe de cod


în același timp (ex: animație imagini, transmiteri simultane de imagini şi
sunete, comunicația cu un server)
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI
Fire de execuție în Java
1. Introducere
❖ Conceptul de multithreading (fire multiple de execuție)
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

A process or program has its own address space and control blocks. It is called
heavyweight because it consumes a lot of system resources. Within a process or
program, we can run multiple threads concurrently to improve the performance.
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

Threads, unlike heavyweight process, are lightweight and run inside a single
process – they share the same address space, the resources allocated and the
environment of that process. It is lightweight because it runs within the context of a
heavyweight process and takes advantage of the resources allocated for that
program and the program’s environment. A thread must carve out its own resources
within the running process. For example, a thread has its own stack, registers and
program counter. The code running within the thread works only within that
context, hence, a thread (of a sequential flow of operations) is also called an
execution context.
Fire de execuție în Java
1. Introducere
❖ Conceptul de multithreading (fire multiple de execuție)
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

Multithreading within a program improves the performance of the program by


optimizing the usage of system resources. For example, while one thread is blocked
(e.g., waiting for completion of an I/O operation), another thread can use the CPU
time to perform computations, resulted in better performance and overall
throughput.
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

Multithreading is also necessary to provide better interactivity with the users. For
example, in a word processor, while one thread is printing or saving the file, another
thread can be used to continue typing. In GUI applications, multithreading is
essential in providing a responsive user interface.

For this article, I shall assume that you understand Swing programming, as Swing
applications rely on multithreading (to perform their specific function, repaint and
process the events) and best to illustrate multithreading.

A typical Java program runs in a single process, and is not interested in multiple
processes. However, within the process, it often uses multiple threads to to run
multiple tasks concurrently. A standalone Java application starts with a single thread
(called main thread) associated with the main() method. This main thread can then
start new user threads.
Fire de execuție în Java
1. Introducere
❖ Fire de execuţie în Java
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

- Limbajul Java suportă multithreading prin clasele disponibile în


pachetul java.lang.
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

- Un fir de execuție lansat de cod este un fir executat separat, având


propria stivă de apeluri.
- Orice aplicație Java pornește cu un fir de execuție principal - cel care
adaugă metoda main() pe poziția cea mai de jos a stivei.
- Firul de execuție principal este lansat de mașina virtuală Java.
- Putem scrie cod care lansează fire de execuții proprii.
Fire de execuție în Java
1. Introducere
❖ Fir de execuție principal. Fir de execuție lansat de cod.
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

fir de execuție principal un alt fir de execuție


lansat de cod

Mașina JVM apelează metoda main( ). Dacă metoda main( ) lansează un nou fir de
execuție, firul de execuție principal poate fi temporar înghețat și începe rularea
noului fir de execuție. Mașina JVM comută execuția între firul nou și firul principal,
până când sunt executate ambele fire.
Fire de execuție în Java
2. Crearea unui fir de execuție
Pentru a dezvolta programe multithread, există două clase și o interfață în pachetul
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

java.lang:
Thread
➢ clasa Thread
void join( )
➢ clasa ThreadGroup
void start ( )
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

➢ interfața Runnable ...


static void sleep( )
Clasa Thread și interfața Runnable oferă suport pentru lucrul cu threaduri ca
entități separate, iar clasa ThreadGroup permite crearea unor grupuri de thread-uri.
Clasa Thread implementează interfața Runnable, iar un obiect ThreadGroup
conține mai multe obiecte de tip Thread.
Pentru a crea un fir de execuție există două variante:
1) Crearea unei clase derivate din clasa Thread.
2) Crearea unei clase care să implementeze interfața Runnable.
Obs. Este preferată a doua metodă din perspectiva orientării pe obiecte.
Fire de execuție în Java
2. Crearea unui fir de execuție
❖Crearea unui fir de execuție prin derivarea clasei Thread
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

1. Crearea unei clase ce extinde clasa Thread și supradefinirea metodei run ().

public class FirExecutie extends Thread {


@Override
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

public void run ( ) {


// codul firului de execuție
}
}

2. Crearea unui fir de execuție

FirExecutie fir = new FirExecutie ( );

3. Lansarea în execuție a firului

fir.start( );
Fire de execuție în Java
2. Crearea unui fir de execuție

❖Crearea unui fir de execuție prin derivarea clasei Thread


FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

Exemplu:

class FirExecutie extends Thread { // firul de execuție


UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

public void run() {


System.out.println(" acest fir se execută ... ");
}
} // sf. Clasa FirExecutie

class TestFir {
public static void main(String [] args ) {
FirExecutie t = new FirExecutie ();
// datorită extinderii clasei Thread putem apela metoda start ()
// și această metodă va apela metoda run ().
//start() este o metodă a clasei Thread.
t.start();
} // sf. main()
} // sf. clasa TestFir
Fire de execuție în Java
2. Crearea unui fir de execuție
❖Crearea unui fir de execuție utilizând interfața Runnable
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

1. Crearea unui obiect Runnable ( obiectul de activitate a firului de execuție)

Runnable threadJob = new MyRunnable ( );


UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

- un obiect Runnable conține metoda care ajunge în partea de jos a stivei


noului fir de execuție: run( ).

2. Crearea unui obiect Thread și transmiterea obiectului Runnable ca parametru

Thread MyThread = new Thread ( threadJob);

- Constructorul clasei Thread va spune obiectului MyThread ce metodă să


adauge în partea de jos a stivei, adică metoda run( ) a obiectului Runnable.
Fire de execuție în Java
2. Crearea unui fir de execuție
❖Crearea unui fir de execuție utilizând interfața Runnable
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

3. Pornirea firului de execuție

MyThread.start ( );
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

- Apelarea metodei start( ) a obiectului Thread înseamnă trecerea de la a


avea doar o instanță Thread la a avea un nou fir de execuție.
- Atunci când își începe execuția, noul fir ia metoda run( ) a obiectului
Runnable și o adaugă în partea de jos a stivei de apeluri a noului fir de
execuție.
Interfața Runnable definește o singură metodă:

public void run ( ) {


// cod ce va fi rulat de noul fir de execuție
}
Fire de execuție în Java
2. Crearea unui fir de execuție
❖ Crearea unui fir de execuție utilizând interfața Runnable
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

Exemplu:

public class MyRunnable implements Runnable {


public void run( ) {
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

go( );
}
public void go( ) {
doMore( );
} 2
public void doMore( ) {
System.out.println(" In varful stivei");
}
}
Fire de execuție în Java
2. Crearea unui fir de execuție
❖ Crearea unui fir de execuție utilizând interfața Runnable
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

class ThreadTest {
public static void main ( String [ ] args) {
Runnable threadJob = new MyRunnable( );
Thread myThread = new Thread(threadJob);
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

myThread.start( ); //
1
System. out. println("Inapoi in main");
}
}

firul de execuție principal noul fir de execuție

1 2
Fire de execuție în Java
2. Crearea unui fir de execuție
❖ Constructori şi metode ale clasei Thread:
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

Thread() Creează un obiect Thread

Thread(Runnable) Creează un obiect Thread dintr-un obiect care implementează interfaţa


Runnable.
Thread(String) Creează un obiect Thread cu un nume specificat
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

Thread(Runnable, String) Creează un obiect Thread cu un nume specificat, dintr-un obiect care
implementează interfaţa Runnable.

run() Implementeză metoda run a interfeţei Runnable. Această metodă trebuie suprascrisă
în toate subclasele şi conţine codul ce este executat de firul de execuţie.
start() Trece firul de execuţie în starea EXECUTABIL, astfel poate fi lansat în execuţie de către
planificatorul JVM.
getName() Returnează numele firului de execuţie.

currentThread() Este o metodă statică ce returnează o referinţă la firul curent aflat în execuţie.

sleep(long) Este o metodă statică ce trece firul curent aflat în execuţie în starea BLOCAT pentru un
număr de milisecunde specificat ca parametru, astfel încât alt fir de execuţie să poată
rula.
Interrupt() Întrerupe execuţia unui fir.

isInterrupted() Returnează true dacă firul de execuţie a fost întrerupt.


Fire de execuție în Java
3. Stările unui fir de execuție
❖ Un fir de execuție se poate afla în una din stările:
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

➢ nou creat: Thread t = new Thread( r);

➢ executabil (runnable): t.start( );


UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

➢ în execuție (running)

➢ blocat (not-runnable) - temporar neexecutabil

➢ terminat

De obicei, un fir de execuție comută între stările executabil și în execuție, pe măsură ce


planificatorul JVM al firelor de execuție selectează un fir și apoi îl întrerupe, astfel încât
să ofere o șansa de a fi lansat în execuţie și altui fir de execuție.
Implementările planificatorului sunt diferite de la o mașină la alta și chiar rularea
aceluiași program pe aceeași mașină poate să ducă la rezultate diferite.
Soluția: se poate influența ordinea de execuţie a firelor adormind periodic fiecare fir
folosind metoda sleep( ).
Fire de execuție în Java
3. Stările unui fir de execuție
Se apelează constructorul
clasei Thread pentru a crea o
1
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

nouă instanţă a clasei Thread.

Firul de execuţie poate ajunge în


Se apelează metoda starea BLOCAT din diferite motive (ex:
NOU start() pentru a trece 4 aşteaptă finalizarea unei operaţii I/O)
2 firul în starea executabil. şi nu va rula din nou până nu va reveni
în starea EXECUTABIL.
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

BLOCAT

Planificatorul JVM de
execuţie a firelor poate
3 decide lansarea în
execuţie a firului.
EXECUTABIL

Firul de execuţie este în starea


TERMINAT odată cu
ÎN AŞTEPTARE
6
terminarea execuţiei metodei
run().

Dacă firul apelează o metodă wait() sau


TERMINAT 5 sleep(), va trece în starea ÎN AŞTEPTARE şi va
rămâne în această stare până când un alt fir
va apela o metodă notify() sau notifyAll() sau
dacă timpul de aşteptare expiră.
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

❖ Uneori programul rulează astfel:


3. Stările unui fir de execuție
Fire de execuție în Java
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

3. Stările unui fir de execuție


❖ Iar alteori programul rulează astfel:
Fire de execuție în Java
Fire de execuție în Java
3. Stările unui fir de execuție
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

Ieșiri ale programului anterior:


% java ThreadTest
Inapoi in main
In varful stivei
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

% java ThreadTest
In varful stivei
Inapoi in main

% java ThreadTest
In varful stivei
Inapoi in main

% java ThreadTest
In varful stivei
Inapoi in main

% java ThreadTest
Inapoi in main
In varful stivei
Fire de execuție în Java
3. Stările unui fir de execuție
❖ “Adormirea” unui fir de execuție:
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

ex.printStackTrace( );
}

-scoate firul de execuție din starea “ în execuție“ și îl ține în așteptare 2


secunde.
- firul nu poate fi selectat pentru rulare decât după ce au trecut cel puțin 2
secunde
- metoda sleep( ) poate lansa o excepție InterruptedException, care este o
excepție verificată de compilator
-La trezire, firul de execuție ajunge în starea executabil și așteaptă să fie
selectat pentru rulare (nu devine automat fir de execuție curent)
Fire de execuție în Java
3. Stările unui fir de execuție
❖ “Adormirea” unui fir de execuție: % java ThreadTest
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

public class MyRunnable implements Runnable { Inapoi in main


public void run( ) {
In varful stivei
go( );
}
public void go( ) { % java ThreadTest
try { Inapoi in main
Thread.sleep(2000); In varful stivei
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

} catch (InterruptedException ex) {


ex.printStackTrace( );
% java ThreadTest
}
doMore( ); Inapoi in main
} In varful stivei
public void doMore( ) {
System.out.println(" In varful stive"); % java ThreadTest
} Inapoi in main
} In varful stivei
class ThreadTest {
public static void main ( String [ ] args) { % java ThreadTest
Runnable threadJob = new MyRunnable( ); Inapoi in main
Thread myThread = new Thread(threadJob); In varful stivei
myThread.start( );
System. out. println("Inapoi in main");
} Apelarea metodei sleep( ) forțează noul fir de execuție să-și întrerupă rularea.
} Firul de execuție principal redevine firul curent și afișează textul “Înapoi in main”.
Programul face apoi o pauză de 2 secunde înainte să ajungă la linia doMore() și
să afișeze textul “In varful stivei”.
Fire de execuție în Java
4. Crearea și lansarea a două fire de execuție
❖ Numele unui fir de execuție
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

-un fir de execuție poate fi denumit folosind metoda setName( ).


- toate firele de execuție primesc nume prestabilite, dar stabilirea unor nume explicite
poate ajuta la urmărirea firelor de execuție
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

Exemplu: lansarea a două fire de execuție

-fiecare fir de execuție are același lucru de făcut: execută un ciclu, afișând numele
firului de execuție curent la fiecare iterație.
- se va crea o instanță Runnable.
- se vor crea cele două fire de execuție, folosind același obiect Runnable (aceeași
sarcină de făcut).
- se denumesc firele de execuție.
- fiecare fir de execuție va parcurge ciclul for afișându-și de fiecare dată numele.
Fire de execuție în Java
4. Crearea și lansarea a două fire de execuție
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

public class TwoThreads implements Runnable {


public static void main (String [ ] args) {
TwoThreads r = new TwoThreads( );
Thread alfa = new Thread ( r);
Thread beta = new Thread ( r);
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

alfa.setName(“Primul fir”);
beta.setName(“Al doilea fir”);
alfa.start( );
beta.start( );
}

public void run ( ) {


for (int i=0; i<25; i++) {
String numeThread = Thread.currentThread( ). getName( );
System.out.println (“i=“+i+ numeThread + “ruleaza”);
}
}
}
Fire de execuție în Java
4. Crearea și lansarea a două fire de execuție
Întrebări:
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

-Firele de execuție vor fi rulate pe rând?


-Vom vedea alternativ numele celor două fire de execuție?
-Cât de des va trece programul de la un fir de execuție la celălalt?
Răspuns: nu știm! Depinde de planificator.
i= 5 Al doilea fir ruleaza
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

i= 0 Primul fir ruleaza i= 19 Primul fir ruleaza


i= 0 Al doilea fir ruleaza i= 11 Primul fir ruleaza i= 14 Al doilea fir ruleaza
i= 1 Primul fir ruleaza i= 6 Al doilea fir ruleaza i= 20 Primul fir ruleaza
i= 1 Al doilea fir ruleaza i= 12 Primul fir ruleaza i= 15 Al doilea fir ruleaza
i= 2 Primul fir ruleaza i= 7 Al doilea fir ruleaza i= 21 Primul fir ruleaza
i= 2 Al doilea fir ruleaza i= 13 Primul fir ruleaza i= 16 Al doilea fir ruleaza
i= 3 Primul fir ruleaza i= 8 Al doilea fir ruleaza i= 22 Primul fir ruleaza
i= 3 Al doilea fir ruleaza i= 14 Primul fir ruleaza i= 17 Al doilea fir ruleaza
i= 4 Primul fir ruleaza i= 9 Al doilea fir ruleaza i= 23 Primul fir ruleaza
i= 4 Al doilea fir ruleaza i= 15 Primul fir ruleaza i= 18 Al doilea fir ruleaza
i= 5 Primul fir ruleaza i= 10 Al doilea fir ruleaza i= 24 Primul fir ruleaza
i= 6 Primul fir ruleaza i= 16 Primul fir ruleaza i= 19 Al doilea fir ruleaza
i= 7 Primul fir ruleaza i= 11 Al doilea fir ruleaza i= 20 Al doilea fir ruleaza
i= 8 Primul fir ruleaza i= 17 Primul fir ruleaza i= 21 Al doilea fir ruleaza
i= 9 Primul fir ruleaza i= 12 Al doilea fir ruleaza i= 22 Al doilea fir ruleaza
i= 10 Primul fir ruleaza i= 18 Primul fir ruleaza i= 23 Al doilea fir ruleaza
i= 13 Al doilea fir ruleaza i= 24 Al doilea fir ruleaza
Fire de execuție în Java
4. Crearea și lansarea a două fire de execuție
❖ Concluzii:
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

-Două sau mai multe fire de execuție care au acces la același obiect pot duce

la alterarea datelor dacă un fir de execuție, de exemplu, iese din rulare în


UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

mijlocul unei operații de manipulare a stării critice a obiectului.

-Pentru a face obiectele sigure din punct de vedere al firelor de execuție,

trebuie să decidem ce metode trebuie să fie rulate până la sfârșit înainte ca

un alt fir de execuție să poată intra în aceeași metodă a aceluiași obiect.


Fire de execuție în Java
5. Prioritatea firelor de execuție
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

- Deși aparent firele de execuție sunt executate simultan, la un moment


dat doar un singur fir are acces la resursele sistem. Fiecare fir de execuție
obține o cuantă de timp în care are acces la resurse.
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

- Managementul accesului firelor de execuție la sistem se face de către


planificatorul (scheduler) firelor de execuție.
- Regulile pe baza cărora planificatorul organizează accesul firelor de
execuție la resurse sunt specifice implementării JVM în funcție de
platformă.
- Totuși un rol în stabilirea acestor reguli îl are mecanismul de priorități.
Fire de execuție în Java
5. Prioritatea firelor de execuție

- fiecărui fir de execuție îî este asociat un nivel de prioritate, ce reprezintă


FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

un număr întreg.
- cu cât acest nivel este mai mare cu atât firul de execuție va avea
prioritate mai mare la resurse, acest lucru este determinat de varianta de
implementare a JVM.
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

- Java pune la dispoziție trei constante pentru selectarea priorităţilor firelor


de execuţie, definite în clasa Thread:
public final static int MAX_PRIORITY; // valoare implicită 10
public final static int MIN_PRIORITY; // valoare implicită 1
public final static int NORM_PRIORITY; // valoare implicită 5

-prioritatea implicită a unui fir de execuție este NORM_PRIORITY.


- pentru a obține prioritatea unui fir de execuție se poate folosi metoda
getPriority( ).
- pentru a atribui o prioritate unui fir de execuție se folosește metoda:
setPriority (int) din clasa Thread.
- planificatorul va scoate din execuție un fir cu prioritate mai mică dacă un
fir de prioritate mai mare devine executabil.
Fire de execuție în Java
6. Sincronizarea firelor de execuție
class Sincro implements Runnable {
private int val;
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

public void run ( ) {


for (int i =0; i<50;i++) {
increment( );
System.out.println(“valoarea este “ + val);
}
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

}
public void increment( ) {
int i=val; // partea critică a codului: adăugăm o unitate la valoarea pe care o
val=i+1; // avea în momentul “citirii” ( nu la valoarea curentă)
}
}
public class TestSincro {
public static void main (String [ ] args) {
Sincro job = new Sincro( ) ;
Thread alfa = new Thread(job);
Thread beta = new Thread(job);
alfa.start( );
beta.start( );
}
}
Fire de execuție în Java
6. Sincronizarea firelor de execuție
❖ problema actualizării pierdute
O posibilă rulare a programului anterior:
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

1) Firul de execuție alfa rulează un timp


- pune valoarea variabilei de instanță val în variabila i
- val este 0, așa că i este acum 0.
- atribuie variabilei val rezultatul adunării i+1
- acum val este 1
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

- pune valoarea variabilei de instanță val în variabila i


- val este 1, așa că i este acum 1
- atribuie variabilei val rezultatul adunării i+1
- acum val este 2

2) Firul de execuție beta rulează un timp


- pune valoarea variabilei de instanță val în variabila i
- val este 2, așa că i este acum 2.
- atribuie variabilei val rezultatul adunării i+1
- acum val este 3
- pune valoarea variabilei de instanță val în variabila i
- val este 3, așa că i este acum 3
În acest moment, firul de execuție beta este trecut în starea executabil,
înainte de a atribui variabilei val valoarea 4!
Fire de execuție în Java
6. Sincronizarea firelor de execuție
❖ problema actualizării pierdute
O posibilă rulare a programului anterior:
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

1) Firul de execuție alfa rulează din nou, continuând de unde a rămas

- pune valoarea variabilei de instanță val în variabila i


- val este 3, așa că i este acum 3.
- atribuie variabilei val rezultatul adunării cu i+1
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

- acum val este 4


- pune valoarea variabilei de instanță val în variabila i
- val este 4, așa că i este acum 4
- atribuie variabilei val rezultatul adunării cu i+1
- acum val este 5

2) Firul de execuție beta rulează din nou, continuând de unde a rămas


- atribuie variabilei val rezultatul adunării cu i+1
- acum val este 4

Firul de execuție alfa actualizase valoarea variabilei la 5, dar apoi a venit


firul de execuție beta, peste ceea ce a făcut alfa, ca și cum actualizarea
făcută de alfa nu s-ar fi produs niciodată.
Fire de execuție în Java
6. Sincronizarea firelor de execuție
❖ problema actualizării pierdute
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

- soluția este: sincronizarea metodei increment( )


- sincronizarea ne asigură de faptul că după ce un fir de execuție intră în
metodă vor fi parcurse toate etapele metodei înainte ca orice alt fir de
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

execuție să poată intra în metodă.


public synchronized void increment( ) {
int i=val;
val=i+1;
}
- cuvântul cheie synchronized împiedică folosirea simultană a metodei de
două fire de execuție
- cuvântul cheie synchronized înseamnă că un fir de execuție are nevoie de
o “cheie” pentru accesul la codul sincronizat.
Fire de execuție în Java
6. Sincronizarea firelor de execuție
❖ problema actualizării pierdute
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

-se poate face sincronizarea la nivelul instrucțiunilor sau grupurilor de instrucțiuni,

nu neapărat la nivelul metodei.


public void go {
met1( );
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

synchronized (this) {
met2( );
met3( );
}
}
Atunci când folosim cuvântul cheie synchronized în interiorul unei metode, nu în
declarația acesteia, trebuie să-i furnizăm ca argument obiectul a cărui cheie trebuie
să o obțină firul de execuție.
Conceptul de monitor: obiect care permite numai și numai unui singur fir de
execuție să apeleze o metodă a obiectului, la un moment dat.
Fire de execuție în Java
6. Sincronizarea firelor de execuție
❖ problema actualizării pierdute
O posibilă execuție a programului după sincronizarea metodei increment( ):
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

1) Firul de execuție alfa rulează un timp


- metoda este sincronizată, așa că obține “cheia” pentru acest obiect
- pune valoarea variabilei de instanță val în variabila i
- val este 0, așa că i este acum 0.
- atribuie variabilei val rezultatul adunării cu i+1
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

- acum val este 1


- returnează cheia ( a terminat metoda increment( ) ).
- Intră din nou în metoda increment( ) și obține cheia.
- pune valoarea variabilei de instanță val în variabila i
- val este 1, așa că i este acum 1
În acest moment, firul de execuție alfa este trecut în starea executabil, dar
nu returnează cheia, deoarece nu a terminat metoda sincronizată.

2) Firul de execuție beta este selectat pentru rulare


- încearcă să intre în metoda increment( ). Metoda este sincronizată, așa că are
nevoie de cheie.
- cheia nu este disponibilă.
În acest moment, firul de execuție beta trebuie să aștepte până când
cheia devine disponibilă.
Fire de execuție în Java
6. Sincronizarea firelor de execuție
❖ problema actualizării pierdute
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

3) Firul de execuție alfa rulează din nou, continuând de unde a rămas


- atribuie variabilei val rezultatul adunării cu i+1
- acum val este 2
- returnează cheia
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

În acest moment, firul de execuție alfa este trecut în starea


executabil, dar nu mai păstrează cheia, deoarece a terminat
metoda increment( ).

4) Firul de execuție beta este selectat pentru rulare


- încearcă să intre în metoda increment( ). Metoda este sincronizată, așa
că are nevoie de cheie.
- cheia este disponibilă, deci o obține.
- pune valoarea variabilei de instanță val în variabila i.

-ș.a.m.d.
Fire de execuție în Java
6. Sincronizarea firelor de execuție
❖ blocajul firelor de execuție
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

- apare atunci când două fire de execuție dețin fiecare câte o cheie de care are
nevoie celălalt fir.
- Java nu are un mecanism pentru rezolvarea blocajelor.
- este sarcina programatorului să proiecteze corect programele, urmărind ordinea în
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

care sunt lansate firele de execuție


Fire de execuție în Java
6. Sincronizarea firelor de execuție
❖ alte metode folosite pentru sincronizare
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

public final void wait( )


public final void wait(long timeout)
public final void wait(long timeout, int nanos )
public final void notify( )
public final void notifyAll( )
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

Exemplu: problema de tip producător-consumator.


while (coadaComenzi.count() == 0) // dacă nu este nici o comandă, se aşteaptă
{
try
{ wait(); // trece firul in starea ÎN AŞTEPTARE
}
catch (InterruptedException e) { }
}

coadaComenzi.add(comanda); // se adaugă o comandă în coada de comenzi


notifyAll(); // informează celelalte fire de execuţie, astfel firele aflate
// în aşteptare vor trece în starea EXECUTABIL.
Fire de execuție în Java
6. Sincronizarea firelor de execuție
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

- prin apelul unui metode wait( ) a unui obiect, firul de execuție din care se face
acest apel trece în starea ÎN AŞTEPTARE.
- firul rămâne în această stare până când un alt fir de execuție va apela una din
metodele notify( ) pentru același obiect.
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

- Se poate specifica în metoda wait( ) durata de timp maximă de așteptare, firul de


execuție va rămâne în aşteptare până când timpul expiră sau până alt fir apelează
metoda notify( ).
- Aceste metode pot fi folosite doar în metode sincronizate, în caz contrar se va
arunca o excepţie IllegalMonitorStateException.
Fire de execuție în Java
7. Întrebări
FACULTATEA DE ELECTRONICĂ, TELECOMUNICAŢII ŞI TEHNOLOGIA INFORMAŢIEI

1. Care este diferenţa între procese şi fire de execuţie?


2. Care sunt modalităţile de creare a unui fir de execuţie? Care metodă este preferată
şi de ce?
3. Care sunt stările unui fir de execuţie?
UNIVERSITATEA TEHNICĂ “GH. ASACHI” DIN IAŞI

4. Care este diferenţa între metodele sleep() şi wait()?


5. Care este diferenţa între sincronizarea unei metode şi sincronizarea unui bloc? De ce
este importantă sincronizarea? Care sunt dezavantajele sincronizării?
6. Ce este un fir daemon?
7. Cum comunică între ele firele de execuţie?
8. Ce face metoda join()?

S-ar putea să vă placă și