Biologie | Chimie | Didactica | Fizica | Geografie | Informatica | |
Istorie | Literatura | Matematica | Psihologie |
Fire (de executare)
Consideram ca lucram pe un calculator cu np³1 procesoare. Ne indreptam atentia asupra modului in care putem lansa in executare mai multe fire de executare (procese).
Un fir (de executare) este un obiect de un tip special, pentru care este precizata o actiune, ce este executata concurent cu actiunile altor fire.
Crearea si lansarea firelor de executare
Clasa Thread
Un prim mod de a crea si lansa in executare fire este oferit de clasa Thread din pachetul java.lang
public class Thread extends Object implements Runnable
clasa ce contine metoda:
public void run()
Aceasta este metoda care va contine actiunile pe care trebuie sa le intreprinda firul. Pentru a preciza respectivele actiuni, va trebuie sa extindem clasa Thread, redefinind in noua clasa metoda run
class Tip extends Thread
alte metode
Crearea si lansarea in executare a unui fir se face astfel:
Tip Ob = new Tip();
Ob.start();
Functioneaza urmatoarea conventie: prin invocarea metodei start este invocata de fapt metoda run; ca urmare firul executa instructiunile din metoda run concurent cu actiunile din firul care l-a lansat si cu eventualele alte fire active.
Executarea concurenta a firelor de executare se face conform modelului aleator, valabil pentru un calculator cu oricate procesoare:
Fiecare procesor executa repetat urmatoarele actiuni:
1) alege aleator un fir de executare 'liber' (ale carui instructiuni nu sunt in curs de executare);
2) executa un timp aleator instructiuni ale sale.
Observatii:
modelul este independent de numarul real de procesoare;
factorul aleator face ca executari diferite ale aceluiasi program (ce foloseste fire de executare) pentru aceleasi date de intrare pot conduce la rezultate diferite.
Cand metoda run se termina, se termina si firul care a invocat-o. Un program se termina atunci cand se termina toate firele de executare lansate din cadrul sau.
Exemplul 7 Programul urmator lanseaza doua fire de executare si in continuare tipareste 200 de ; cele doua fire tiparesc cate 200 de , respectiv de . Ca urmare a utilizarii modelului aleator, la fiecare executare vor aparea 200 de , 200 de si 200 de , in diferite ordini.
class Tip extends Thread
public void run()
class Fire
Observatie. Daca nu s-ar apela la conventia de mai sus si Ob1 si Ob2 ar invoca metoda run, atunci firul care invoca aceasta metoda nu si-ar continua activitatea si ar astepta ca cele doua obiecte sa termine de executat metoda run, deci s-ar renunta la esenta firelor: executarea lor concurenta! Concret, vor aparea 200 de , urmati de 200 de si de 200 de
Observatie. Firul care lanseaza un nou fir nu are drepturi suplimentare: de exemplu se poate termina inaintea celui pe care il lanseaza.
Exemplul 8 Consideram programul urmator:
import java.util.*;
class Tip extends Thread
public void terminare()
class P1
Pe baza obiectului Ob este lansat un fir de executare. Acesta va tipari, atata timp cat variabila booleana b are valoarea true sirul numerelor naturale. Firul de executare principal prevede citirea repetata de siruri de caractere, pana cand este introdus un sir ce incepe cu caracterul 'q' in acel moment obiectul Ob executa metoda terminare, care modifica valorii lui b in false; ca urmare firul de executare lansat este oprit. Firul de executare principal se termina si el.
Acest exemplu arata ca obiectul pe baza caruia este lansat un fir de executare (Ob in cazul nostru) nu este ocupat si deci poate invoca in continuare metode care sunt executate concurent cu actiunile firului.
Daca in loc de Ob.start() am fi folosit Ob.run(), programul ar rula la infinit.
Interfata Runnable
O a doua modalitate de a crea si lansa in executare fire este de a folosi interfata Runnable din pachetul java.lang si care anunta numai metoda run
class Tip implements Runnable
. . .
class C
Exemplul 9. Reluam Exemplul 8, utilizand interfata Runnable in loc de clasa Thread
import java.util.*;
class Tip implements Runnable
public void terminare()
class P2
În acest exemplu apare faptul
ca obiectul
Un prim mod de sincronizare
Daca dintr-un fir lansam alt fir si dorim sa asteptam terminarea acestuia inainte de a trece la urmatoarea actiune, vom invoca metoda join a clasei Thread
public final void join() throws InterruptedException
Daca modificam programul din Exemplul 7, inserand dupa:
Ob1.start(); Ob2.start();
actiunea:
try
catch(InterruptedException e)
cele 200 de caractere '0' vor fi tiparite ultimele.
Realizarea excluderii reciproce
În mod frecvent, actiunile intreprinde de mai multe fire de executare active se refera la unele resurse comune (variabile, obiecte, fisiere, baze de date etc.). În acest caz pot aparea aspecte nedorite, specifice programarii concurente. Ne rezumam la problema excluderii reciproce, ce reclama ca la fiecare moment de timp cel mult un fir de executare sa aiba acces la resursele comune; daca un fir incearca sa acceseze resursele comune cand un alt fir le acceseaza, el va fi blocat.
Problema atribuirii multiple. Mai multe fire executa in mod repetat instructiunea n n+1 asupra variabilei comune n. Rezultatul final poate sa nu fie cel corect deoarece:
variabila n reprezinta resursa comuna;
instructiunea n n+1 nu este atomica, ci consta in atribuirile:
r n; r r+1; n r (r este un registru al memoriei);
este folosit modelul aleator.
Fie S secventa de instructiuni ce trebuie executata sub excludere reciproca, adica secventa de instructiuni care face referire la resursele comune. Mecanismul propus de Java pentru asigurarea excluderii reciproce este urmatorul:
Exemplul 10. Rezolvarea problemei atribuirii multiple.
class C
catch(InterruptedException e)
}
void incr()
class Tip extends Thread
public void run()
}
class AtribMult
catch (InterruptedException e)
System.out.println('nn = ' + C.n);
}
Este usor de verificat ca daca nu declaram metoda incr cu modificatorul synchronized sau daca firele nu invoca metoda incr prin intermediul aceluiasi obiect de tipul C, rezultatul final nu va fi neaparat cel corect.
Copyright © 2024 - Toate drepturile rezervate