Sunteți pe pagina 1din 11

Laboratorul 2

Laboratorul 2
Fire de execuie n Java SE Noiuni generale
1.Obiectivele laboratorului

nsuirea conceptelor
o fire de execuie
o strile firelor
gestionarea firelor
o crearea firelor
o startarea firelor
o oprirea firelor
setarea prioritilor firelor

2. Consideraii teoretice i exemple de aplicaii


Firele de execuie sunt secvene ale unui program (proces) ce se execut efectiv sau
virtual n paralel n cadrul unui singur proces. Acestea sunt create i apoi startate, fiind lsate
s evolueze liber sau controlat.
2.1. Strile unui fir de execuie
Un fir de execuie se poate afla n una dintre urmtoarele stri:
1. Inexistent (nonexistent) obiectul fir de execuie nu a fost creat.
2. Creat (New) obiectul fir de execuie a fost creat dar nc nu a fost startat.
3. Gata de execuie (runnable) firul se afl n starea n care poate fi rulat n momentul n
care procesorul devine disponibil.
4. n execuie (execution=running) firul se afl n execuie.
5. Terminat (dead) calea normal prin care un fir se termin este prin ieirea din metoda
run().
6. n ateptare, blocat (waiting=blocked) firul de execuie este blocat i nu poate fi rulat,
chiar dac procesorul este disponibil, pn cnd este ndeplinit o condiie pentru
deblocarea lui.
Un fir poate intra n starea blocat urmtoarele situaii:
-

firul a apelat metoda Thread.sleep(sec) care determin blocarea firului pentru un


numr specificat de secunde;
firul a apelat o metod sincronizat care are monitorul acaparat de ctre un alt fir;
a fost apelat metoda wait();
firul ateapt dup o operaie (cu fluxuri) de intrare ieire [ORA, 2012b];

2.2 Crearea i startarea firelor de execuie


La startarea unei aplicaii (program) Java se ncepe cu execuia metodei main(). Pentru
a crea fire de execuie suplimentare n Java se pot utiliza dou procedee: extinderea clasei
Thread sau implementarea interfeei Runnable. Vor fi descrise cele dou mecanisme prin
intermediul crora pot fi construite fire de execuie n Java Standard.
13

Fire de execuie n Java SE noiuni generale

2.2.1. Extinderea clasei Thread


Un fir de execuie poate fi construit plecnd de la o clas definit de utilizator i
motenind (extinznd) clasa Thread. Clasa Thread este o clas definit n cadrul pachetului
java.lang (unul dintre pachetele Java Standard) i aceast clas definete toate proprietile i
funcionalitile unui fir de execuie. O clas care extinde clasa Thread devine clas de tip fir
de execuie astfel nct un obiect instan al acestei clase va putea fi folosit pentru a lansa n
execuie un fir.
Exemplu:
class Sortare extends Thread {
public void run(){
// activitile desfurate de ctre firul de executie

}
}

O clas de tip fir de execuie va trebui s suprascrie metoda run(), motenit din cadrul
clasei Thread. n cadrul acestei metode va trebui definit secvena de instruciuni ce va fi
executat de ctre firul de execuie. Pentru a lansa n execuie un fir se folosete metoda
start(), motenit de asemenea din cadrul clasei Thread. Aceast metod este responsabil cu
iniializarea tuturor mecanismelor necesare pentru a putea executa un fir de execuie, dup
care apeleaz automat metoda run().
Exemplu:
Specificaii: Se cere conceperea unei aplicaii care creeaz pe lng firul principal
(main), alte 3 fire. Fiecare fir implementeaz un contor pe care-l incrementeaz periodic
numrnd iteraiile. Firul scrie pe ecran numele lui i indicele interaiei. Firele se vor construi
prin extinderea clasei Thread.
Pentru faza de proiectare a aplicaiei sunt propuse: diagrama claselor, prezentat n
Figura 2.1a) i diagrama de activiti, prezentat n Figura 2.2.
Pentru faza de implementare a aplicaiei se propune Secvena de cod 1. n aceast
secven de cod 1, dac se nlocuiete apelul metodelor start() cu cel al metodelor run(), se va
obine executarea celor trei secvene de instruciuni pe un singur fir de execuie, adic pe firul
principal . Acesta din urm este creat implicit n momentul executrii metodei main().

a)

b)
Figura 2.1 Diagramele claselor

14

Laboratorul 2

Figura 2.2 Diagrama de activiti


Secvena de cod 1
class Main{
public static void main(String[] args){
Counter c1 = new Counter("counter1");
Counter c2 = new Counter("counter2");
Counter c3 = new Counter("counter3");
c1.start(); //c1.run();
c2.start(); //c2.run();
c3.start(); //c3.run();
}
}
class Counter extends Thread {
Counter(String name){
super(name);
}
public void run(){
for(int i=0;i<20;i++){
System.out.println(getName() + " i = "+i);
try {
Thread.sleep((int)(Math.random() * 1000));
}catch (InterruptedException e) {e.printStackTrace();}
}
System.out.println(getName() + " job finalised.");
}
}

15

Fire de execuie n Java SE noiuni generale

2.2.2. Implementarea interfeei Runnable


Avnd n vedere faptul c Java nu accept motenirea multipl, se folosete
implementarea interfeei Runnable pentru a crea fire de execuie care n acelai timp vor
trebui s moteneasc o alt clas.
Exemplu:
Specificaii: Se cere conceperea unei aplicaii care creeaz pe lng firul principal
(main), alte 3 fire. Fiecare fir implementeaz un contor pe care-l incrementeaz periodic
numrnd iteraiile. Firul scrie pe ecran numele lui i indicele interaiei. Firele se vor construi
folosind interfaa Runnable.
Proiectarea aplicaiei s-a realizat prin intermediul diagramei claselor din Figura 2.1b.
Diagrama de activiti este aceeai ca n cazul aplicaiei precedente (vezi Figura 2.2).
Implementarea aplicaiei este prezentat n Secvena de cod 2.
Secvena de cod 2
public class CounterRunnable implements Runnable {
public void run(){
Thread t = Thread.currentThread();
for(int i=0;i<20;i++){
System.out.println(t.getName() + " i = "+i);
try { Thread.sleep((int)(Math.random() * 1000));}
catch (InterruptedException e) {e.printStackTrace();}
}
System.out.println(t.getName() + " job finalised.");
}
}
class Main{
public static void main(String[] args) {
CounterRunnable c1 = new CounterRunnable();
CounterRunnable c2 = new CounterRunnable();
CounterRunnable c3 = new CounterRunnable();
Thread t1 = new Thread(c1,"conuter1");
Thread t2 = new Thread(c2,"conuter2");
Thread t3 = new Thread(c3,"conuter3");
t1.start();
t2.start();
t3.start();
}
}

n momentul apelrii metodei start() din cadrul obiectului de tip Thread, se va executa
metoda run() din cadrul obiectului transmis ca argument la crearea acestuia.
Alternativ se poate crea o metoda start() n clasa CounterRunnable (vezi exemplul de
mai jos), n corpul creia se va crea i starta firul de execuie. Astfel, vor putea fi tratate unitar
firele de execuie implementate prin extinderea clasei Thread cu cele create prin
implementarea interfeei Runnable.

16

Laboratorul 2

Exemplu:
public void start(){
new Thread(this).start();
}

2.3 Oprirea firelor de execuie


Calea recomandat de terminare a unui fir este prin revenirea normal, adic execuia
instruciunii return din run() sau terminarea tuturor instruciunilor firului. n cadrul metodei
run() se pot aduga blocuri condiionale care s determine terminarea firului de execuie,
respectiv ieirea din metoda run().
n momentul n care un fir este blocat, datorit execuiei unor instruciuni wait(),
sleep(), join() sau a unor operaii I/O, acesta nu poate verifica nici o condiie. Pentru a fora
terminarea unui fir care este blocat se poate utiliza metoda interrupt(), dar aceasta nu este
cea mai potrivit. Aceast metod determin aruncarea unei excepii InterruptedException
care trebuie tratat.
O metod recomandat de terminare a execuiei unui fir este construirea unei metode
stop(), care va folosi o variabil logic pentru controlul execuiei.
Exemplu:
public void stop(){
this.loop=false;//loop folosit ca variabil logic pentru buclare
}
public void run(){

while (this.loop){
//... secventa de instructiuni
}

2.4 Setarea prioritilor firelor de execuie


Prioritatea unui fir de execuie furnizeaz planificatorului informaii legate de
importana firului respectiv. Planificatorul implicit ordoneaz lista gata de execuie n funcie
de prioritile setate. Pentru a seta prioritatea unui fir se utilizeaz metoda setPriority(), iar
pentru a afla prioritatea unui fir se utilizeaz metoda getPriority(), metodele fac parte din
clasa Thread. Firele pot primi prioriti aflate ntre valorile MIN_PRIORITY=1 i
MAX_PRIORITY=10, acestea fiind constante definite n clasa Thread. Prioritatea implicit a
unui fir este prioritatea firului care l-a creat.
Prioritile utilizate de maina virtual Java depind de facilitile oferite de sistemul
de operare pe care este implementat.
3. Dezvoltri i teste
3.1. Aplicaia 1:
3.1.1. Cerine: S se implementeze o aplicaie pentru determinarea numrului de procesoare
logice (core-uri i/sau thread-uri) ale sistemului de calcul.
3.1.2. Specificaii:
1. Aplicaia va fi implementat n Java 2 SE.
17

Fire de execuie n Java SE noiuni generale

2. Aplicaia va porni mai multe fire de execuie, fiecare avnd o prioritate diferit. Firele de
execuie vor incrementa cte un contor.
3. Aplicaia va avea o interfa grafic n care vor fi afiate valorile contoarelor sub forma
unor bare de progres.
4. Numrul barelor mai rapide, care vor avansa relativ deodat n ciuda prioritilor
diferite va da numrul de procesoare logice.
3.1.3. Proiectarea aplicaiei:

Figura 3.1 Diagrama claselor

Figura 3.2 Diagrama secvenial


n diagrama din Figura 3.1 s-au considerat dou fire de execuie create de ctre
aplicaie. Un fir de execuie va lucra iterativ (n bucl) pn cnd bara de progres asociat se
va umple. Pe fiecare iteraie, un fir de execuie va executa o activitate (n scopul ncrcrii
procesorului), apoi va incrementa contorul, respectiv va actualiza valoarea din bara de progres
asociat prin parametrul id.

18

Laboratorul 2

3.1.4. Implementare:
Secvena de cod 3: clasa Main
public class Main {
private static final int noOfThreads=6;
private static final int processorLoad=1000000;
public static void main(String args[]){
Window win=new Window(noOfThreads);
for(int i=0;i<noOfThreads;i++){
new Fir(i,i+2,win,processorLoad).start();
}
}
}
Secvena de cod 4: clasa Window
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JProgressBar;
public class Window extends JFrame{
ArrayList<JProgressBar> bars=new ArrayList<JProgressBar>();
public Window(int nrThreads) {
setLayout(null);
setSize(450,400);
setDefaultCloseOperation(EXIT_ON_CLOSE);
init(nrThreads);
this.setVisible(true);
}
private void init(int n){
for(int i=0;i<n;i++){
JProgressBar pb=new JProgressBar();
pb.setMaximum(1000);
pb.setBounds(50,(i+1)*30,350,20);
this.add(pb);
this.bars.add(pb);
}
}
public void setProgressValue(int id,int val){
bars.get(id).setValue(val);
}
}
Secvena de cod 5: clasa Fir
public class Fir extends Thread {
int id;
Window win;
int processorLoad;
Fir(int id,int priority,Window win, int procLoad){
this.id=id;
this.win=win;
this.processorLoad=procLoad;
this.setPriority(priority);
}
public void run(){
int c=0;
while(c<1000){
for(int j=0;j<this.processorLoad;j++){
j++;j--;
}
c++;
this.win.setProgressValue(id, c);
}
}
}

19

Fire de execuie n Java SE noiuni generale

3.2. Aplicaia 2
3.2.1. Cerine: Modificai aplicaia prezentat ca exemplu la punctul 3.1 astfel nct
remprosptarea interfeei s se realizeze prin intermediul design pattern - ului MVC, folosind
mecanismul Observer-Observable.
Elaborai specificaiile aplicaiei dup modelul de mai sus.
Se vor modifica att diagramele propuse pentru proiectare, ct i codul aplicaiei.
3.3. Aplicaia 3
3.3.1. Cerine: S se implementeze n Java 2 SE o aplicaie care are trei fire de execuie.
3.3.2. Specificaii:
1. Aplicaia va fi implementat n Java 2 SE.
2. Aplicaia are o interfa grafic n care vor fi adugate trei forme geometrice (de exemplu
ptrate), dispuse iniial n partea superioar a ferestrei.
3. Fiecare fir de execuie este responsabil cu deplasarea ptratelor, nspre partea inferioar a
ferestrei, cu o vitez constant, calculat aleator (ntre un minim i un maxim) pentru fiecare
ptrat n parte.
4. Firele de execuie vor fi oprite n momentul n care formele geometrice ies din perimetrul
ferestrei. Pentru oprirea firelor se va defini metoda stop(), care s foloseasc o variabil
logic.
3.3.3. Se cer:
a) diagrama claselor;
b) diagrama de activiti;
c) diagrama secvenial;
d) programul surs.
3.3.4. Se va testa dac aplicaia:
deschide interfaa grafic;
creeaz cele 3 forme geometrice;
deplaseaz cele 3 forme geometrice;
realizeaz oprirea firelor cu metoda stop() definit.
3.4. Aplicaia 4
3.4.1. Cerine: Se va modifica aplicaia de la punctul 3.3 astfel nct n partea inferioar a
aplicaiei va fi adugat o nou form geometric (de exemplu un cerc). Utilizatorul va putea
deplasa cercul prin intermediul tastaturii, n stnga sau n dreapta. Aplicaia va avea un al
patrulea fir de execuie cu rol de supervizor. n momentul n care cercul intr n coliziune cu
unul dintre ptrate, toate formele geometrice din fereastr se vor opri i se va afia n fereastr
un mesaj de eroare. n aceast aplicaie, firele responsabile cu deplasarea ptratelor vor evolua
n bucl (n momentul n care un ptrat iese din fereastr, acesta i va relua poziia iniial).
Utilizatorul va putea relua jocul de trei ori. Pentru a face jocul mai interesant se va calcula un
punctaj. Acesta va fi calculat prin nsumarea ptratelor evitate cu succes.
3.4.2. Se cere:
a) diagrama claselor;
b) diagrama de activiti;
c) diagrama secvenial;
d) programul surs.
20

Laboratorul 2

3.4.3. Se va testa dac aplicaia:


deschide interfaa grafic;
este adugat noua form geometric;
afieaz mesajul de eroare cnd se ciocnesc figurile;
reia jocul de la starea iniial;
poate relua jocul de trei ori;
calculeaz corect punctajul.
4. Verificarea cunotinelor
1. Definii conceptul de fir de execuie.
2. Care este diferena dintre un fir de execuie i un proces?
3. Care sunt tehnicile prin care se pot implementa fire de execuie n Java? n ce situaii se
folosete fiecare?
5. Care este metoda prin apelul creia se pornete execuia firului?
6. Care este metoda ce conine logica (secvena de instruciuni) firului de execuie?
7. La ce se refer prioritatea unui fir de execuie? Cte niveluri de prioritate exist n Java?
Care este prioritatea implicit a unui fir de execuie?
8. Numii cel puin 4 metode definite n clasa Thread.

21

Fire de execuie n Java SE noiuni generale

22

Capitolul 1