CATEGORII DOCUMENTE |
Tratarea firelor de executie
Aplicatiile moderne trebuie sa permita in anumite situatii executia simultana a mai multor prelucrari diferite (afisare imagini, preluare fisiere din retea, etc). Limbajul Java poseda un mecanism care permite programarea unor activitati simultane sub forma firelor de executie (thread-uri). Toate firele de executie dintr-un program (proces) impart acelasi spatiu de adrese (aceleasi variabile). Acest aspect usureaza comunicarea intre firele de executie prin intermediul unora dintre variabile. Utilizarea firelor de executie nu micsoreaza timpul de executie al aplicatiilor ci le fac mai usor de scris deoarece se poate scrie cate un program pentru fiecare activitate ce trebuie controlata de catre aplicatie.
Mecanismul de fir de executie este descris de calasa Thread din biblioteca java.lang. Clasa Thread contine metoda run() care, aici, nu este implementata. Acest lucru trebuie facut intr-o clasa care extinde clasa Thread. Firele de executie ale aplicatiei vor fi instante ale acestei noi clase. Codul care va fi executat de catre firul de executie este continut in metoda run().
Class NewThread1 extends Thread
..
}
Aceasta este o prima metoda de definire a firelor de executie. O a doua metoda consta in "adaugarea" la o clasa a facilitatilor din interfata Runnable care are prevazuta, deasemenea, metoda run().
Class NewThread2 implements Runnable
...
}
In primul caz, instantierea unui fir de executie se face sub forma
NewTread1 fir = new NewThread1();
iar in al doilea caz
NewThread2 f = new NewThread2();
Thread fir = new Thread(f);
In cazul firelor de executie instantiate dupa a doua metoda nu se pot apela in metoda run() metode specifice obiectelor Thread (sleep(), setPriority(), getPriority()). Desi firul de executie este instantiat, executia sa nu poate incepe decat dupa invocarea metodei start().
fir.start();
Ca urmare a executiei acestei metode firul de executie este pregatit pentru executie dar aceasta nu incepe imediat. In cazul in care firul este creat dupa prima metoda si se doreste pornirea lui imediat dupa instantiere atunci constructorul clasei care extinde pe Thread trebuie sa contina apelul lui start().
public NewThread1 (<lista parametri>)
Daca exista mai multe fire de executie care se executa pe un singur procesor, se pune problema alegerii firului care se executa la un moment dat. Aceasta se face in functie de prioritatea firelor de executie. Orice cod Java se executa intr-un fir de executie. La creare, un fir de executie are un nivel de prioritate egal cu cel al firului din care a fost creat. Prioritatea i se poate modifica prin metoda setPriority() (se pot da valori intre Thread.Min_Priority = 1 si Thread.Max_Priority = 10). Executia a doua fire cu aceeasi prioritate se face in mod diferit functie de sistemul de operare pe care se executa.
Daca sistemul de operare admite divizarea timpului atunci fiecarui proces i se aloca o cuanta de timp dupa care este intrerupt si executia continua cu alt fir. In sistemele fara divizare a timpului, un fir de executie cedeaza controlul procesorului prin apelul explicit al metodei yield() sau prin apelul unei metode care conduce la autoblocare sleep(), wait().
Un fir de executie poate fi intr-una din situatiile : creat, gata de executie, suspendat, terminat.
1 Sincronizarea firelor de executie
In cazul cand doua procese se executa simultan, probelma sincronizarii apare daca cele doua procese concura la utilizarea acelorasi resurse sau daca coopereaza intre ele.
Daca procesele, in cazul nostru firele de executie, sunt in concurenta atunci este necesar ca gestionarea resurselor partajate sa se faca consistent. Aceasta inseamna ca la un moment dat un singur fir are acces la resursele comune. Rolul sincronizarii este acela de a asigura accesul exclusiv la resursele comune. Secventa de cod care asigura accesul exclusiv se numeste regiune critica.
Daca procesele coopereaza atunci ele trebuie sa schimbe informatii. In acest caz sincronizarea presupune ca procesele sa se astepte unul pe altul pana cand isi pot transmite informatiile necesare. Regiunea critica contine acel cod program care asigura schimbul de informatie.
Sa consideram cazul firelor de executie concurente. Primul exemplu este cel a doua instante ale unei clase, FirNeSyncro, care extinde clasa Thread. Partajarea aceleiasi resurse, anume o instanta a clasei AccesComun va genera rezultate eronate. Pentru a se observa mai bine acest aspect am introdus blocajul firului curent prin apelul metiodei sleep().
public class AccesComun
void metoda(int numar)catch (InterruptedException e)
b++;
}
}
class FirNeSyncro extends Thread
public void run()
}
public class NeSynchro
}
Rezultatul rularii este :
Din firul 1 : a = 0, b = 0
Din firul 2 : a = 0, b = 0
Din firul 1 : a = 2, b = 1
Din firul 2 : a = 3, b = 2
Din firul 1 : a = 4, b = 3
Din firul 2 : a = 5, b = 4
si arata ca cele doua variabile a si b nu sunt actualizate corect.
Solutia corecta presupune sincronizarea accesului la obiectul partajat si se realizeaza cu ajutorul secventelor sau metodelor ce se executa in excludere mutuala. Implementarea foloseste un mecanism de tip zavor. Acesta presupune declararea unor metode sau secvente de cod sincronizate (atributul synchronized). Pentru a executa metoda sau secventa declarata synchronized firul de executie inchide zavorul. Cat timp zavorul este inchis nici un alt fir nu poate executa metoda sau secventa respectiva. Un fir de executie care incearca executia unei metode sau secvente "inchise" este blocat si trecut intr-o coada de asteptare. Cand se termina executia unei metode cu atributul synchronized zavorul este deschis si se preia din coda de asteptare unul dintre firele blocate care trece in starea gata de executie.
class FirSyncro extends Thread
void metoda()catch (InterruptedException e)
b++;
}
public void run()
System.out.println(this.getName()+' Gata !');
}
}
public class Synchro2
}
Obiectul o are doar rolul de a furniza zavorul. Zavorul poate fi asociat unei clase
synchronized(getClass())
sau chiar functiei metoda(),
synchronized void metoda()
Daca metoda ar fi statica atunci zavorul ar fi asociat chiar clasei din care face parte.
Executia programului va actualiza concomitent, deci corect, variabilele a si b.
Urmatorul exemplu considera cazul proceselor care colaboreaza. Instantele claselor Profesor si Elev sunt fire de executie care comunica prin intermediul unei instante a clasei ZonaTampon. Aceasta clasa contine date pentru coeficientii coeficientii unei ecuatii si valoarea radacinii. Profesorul propune o ecuatie iar elevul o rezolva. Elevul nu poate rezolva ecuatia pana cand nu primeste datele necesare in instanta ZonaTampon. Profesorul nu propune o alta ecuatie pana cand nu primeste rezultatul la problema pusa. Cheia programului se afla in clasa ZonaTampon care contine doua metode sincronizate.
public class Ecuatie
}
public class ZonaTampon
public synchronized float a_Calculat(int numar)catch (InterruptedException e)
}
valoare=-b/a;
System.out.println(' iar elevul '+numar+' a calculat '+valoare+'tn');
disponibil=false;
notify();
return valoare;
}
public synchronized void a_Propus(float a,float b,int numar)catch (InterruptedException e)
}
this.a=a;this.b=b;valoare=100000;
System.out.print('Profesorul '+numar+' a propus '+a+'x+'+b+'=0');
disponibil=true;
notify();
}
}
class Elev extends Thread
int getNumar()
public void run()
}
}
class Profesor extends Thread
int getNumar()
public void run()catch (InterruptedException e)
}
}
}
Politica de confidentialitate | Termeni si conditii de utilizare |
Vizualizari: 795
Importanta:
Termeni si conditii de utilizare | Contact
© SCRIGROUP 2024 . All rights reserved