Sunteți pe pagina 1din 17

Concurenta in Java – curs 12

Noțiuni de bază
- Informatică Economică, an III –

Gheorghe Cosmin Silaghi

Cluj-Napoca - 26 mai 2021


Introducere in programarea concurenta
Programele scrise pana acuma: secventiale
Programare concurenta: mai multe fire de executie care ruleaza in
paralel
Exemple de utilizare a modelului concurent de executie in Java:
 Sistemul web clasic
 JSP
 Swing si SWT au mecanisme pentru suport concurenta
Motive pentru a realiza programe concurente
 Executie mai rapida – in conditiile programarii multiprocesor
 Imbunatatirea code design

Concurenta induce un cost: complexitate sporita a programelor

Cluj-Napoca - 26 mai 2021


Executia mai rapida a programelor
Tendinta curenta: numar mai mare de core-uri, in conditiile plafonarii vitezei
chipurilor
Prin distribuirea takurilor pe procesoare se creste throughput
Chiar in conditiile single core, programele concurente se pot executa mai rapid
(datorita situatiilor blocking)
Daca un task (sau thread) nu poate continua (de ex. datorita operatiilor de I/O), se
spune ca acel task e blocat.
event-driven programming: realizarea de interfete grafice responsive, in conditiile in
care prelucrarile asociate unor evenimente dureaza

Un proces este un program de sine statator cu propriul spatiu de adrese


Un sistem de operare multi-tasking poate sa ruleze mai multe procese la un moment
dat (datorita schimbarii periodice a CPU de la un proces la altul) – implementarea
concurentei la nivel de SO
Implementarea concurentei la nivel de mediu de programare: presupune existenta
unor resurse comune si coordonarea utilizarii acestor resurse de catre threaduri. Mai
mult, procesele pot comunica intre ele

Cluj-Napoca - 26 mai 2021


Tipuri de sisteme paralele

Shared-memory Distributed-memory

Cluj-Napoca - 26 mai 2021


Abordari ale concurentei in LP (I)
Taskurile concurente sa fie izolate unele de altele (fiecare functie
concurenta nu produce side effects) – modelul distributed memory –
ex. Erlang (Erricson)

C/C++: fork: se creaza procese separate gestionate de catre SO


Java: in cadrul unui singur proces gestionat de catre SO, se creaza
mai multe taskuri prin threading
C/C++ / Java – modelul shared memory

Cluj-Napoca - 26 mai 2021


Abordari ale concurentei (II)
Java threading este preemtive: mecanismul de scheduling furnizeaza o felie
de timp procesor fiecarui thread, prin intreruperea periodica a threadului
care se executa si schimbarea contextului de executie catre un alt thread
Intr-un sistem multithreading cooperativ fiecare thread isi lasa controlul
catre alt thread la un anume moment => programatorul trebuie sa insereze
un soi de yield

Cluj-Napoca - 26 mai 2021


Code design
Unele probleme (precum cele de simulare) sunt concurente prin definitia lor
Chiar daca sistemul pe care programul se executa are un singur CPU, programele
concurente au o claritate mai mare

Java threading este preemtiv => suport pentru numar limitat de threaduri (de
ordinul zecilor) -> poate fi limitativ in anumite situatii
Cooperative multithreading: nu exista o limita a taskurilor independente care pot
rula la un moment dat

Concurenta este benefica daca se lucreaza cu arhitecturi moderne de tip


messaging - sisteme distribuite
Prin messaging se realizeaz coordonarea proceselor intre ele (fara sa fie nevoie de
partajarea de resurse)

Cluj-Napoca - 26 mai 2021


Threading in Java
Thread: un flux secvential de executie dintr-un proces
Intr-un sistem multi-threading, un proces poate contine mai multe
threaduri concurente
Programatorul proate programa fiecare dintre aceste threaduri ca si cum ar
avea intreg procesorul la dispozitie

Pentru a defini un task trebuie implementara interfata Runnable


In general, metoda run a aceste interfete are o bucla care se executa atata
timp cat este necesar

Fct main are alocat propriul thread. Pt un task nou, trebuie sa se creeze un
obiect dintr-o clasa care implementeaza Runnable

Cluj-Napoca - 26 mai 2021


Terminologie
In Java exista distinctie intre taskul care este executat si threadul care
executa acest task
Obiectele care implementeaza Runnable sunt taskuri, iar threadurile ajuta la
executia acestor taskuri
Crearea unui thread este o operatie costisitoare (bazata low-level pe
conceptul de pthread din C) -> are sens ca sa gestionam threadurile cu
grija
-> distinctia task – thread are sens
Terminologie:
Task: un anume job care trebuie realizat
Thread: mecanismul care executa taskul.

Cluj-Napoca - 26 mai 2021


Clasa Thread
Pentru a crea un thread, trebuie furnizat un obiect de tip Runnable
in constructorul unui obiect de tip Thread
Metoda start a clasei Thread realizeaza toate initializarile necesare si apoi
apeleaza metoda run a obiectului Runnable agregat. Metoda run este
apelata intr-un fir nou de executie

Mecanismul pentru lansarea threadurilor in executie este non-deterministic


(nu putem garanta ordinea in care schedulerul aloca procesorul diverselor
taskuri)
Thread.yield() -> solicita JVM sa dea controlul unui alt thread din programul
curent – pentru a solicita invocarea schedulerului
Garbage collectorul nu va colecta un thread nereferit decat dupa ce acesta
isi termina executia propriului run

Cluj-Napoca - 26 mai 2021


Variatii la crearea taskurilor
1. se creaza o clasa care implementeaza Runnable. Un obiect din
aceasta clasa e transmis in constructorul unui obiect de tip Thread
2. se mosteneste din clasa Thread, si se suprascrie metoda run
3. se creaza o clasa care implementeaza Runnable. Aceasta clasa
agrega un obiect de tip Thread construit prin new Thread(this)
Atentie: la metodele 2 si 3 taskurile sunt pornite din constructor (cu
start). -> e problematic, threadul isi poate incepe executia inainte ca
constructorul sa se termine
=> se prefera varianta 1 si utilizarea executorilor

Clasele care implementeaza Runnable sau exting Thread pot fi scrise si


ca si clase inner (eventual anonime) !!!

Cluj-Napoca - 26 mai 2021


Executors
Java furnizeaza un nivel intermediar intr-un client si taskurile pe care acesta le
executa. In loc ca clientul sa apeleze taskurile in mod direct, un obiect intermediar
(executor) va apela aceste taskuri indirect
Executors gestioneaza ciclul de viaza a taskurilor asincrone fara sa fie nevoie sa
gestionam explicit ciclul de viata a unui obiect Thread

Se creaza un ExecutorService prin apelarea unei metode specifice a clasei Executors


Metoda shutdown: previne ca alte taskuri sa fie trimise catre executorService spre
executie
Tipuri de ExecutorService:
 FixedThreadPool: fixeaza de la inceput numarul de threaduri utilizate pentru
executia taskurilor. Este o metoda deosebit de eficienta pt ca overheadul cu
crearea threadurilor este realizat la crearea obiectului de tip ExecutorService
 CachedThreadPool: permite un numar variabil de threaduri. Va opri crearea de
threaduri noi pe masura ce threadurile vechi sunt reciclate
 SingleThreadExecutor este un FixedThreadPool cu un singur thread (de
obicei pentru long-lived thread – ex. Treaduri care asculta un socket)

Cluj-Napoca - 26 mai 2021


Crearea de threaduri pt Executors

ThreadFactory: interfata pentru crearea de threaduri la cerere.


Threadurile pot fi personalizate (de exemplu, threaduri daemon) –
metoda newThread
Obiecte implementand ThreadFactory pot fi furnizate ca si constructori
pentru Executori; executor service-ul rezultat va utiliza acest
threadFactory pentru crearea noilor threaduri (cu metoda newThread)

Cluj-Napoca - 26 mai 2021


Returnarea de valori din taskuri
Interfata Callable: metoda call care trebuie sa returneze o valoare
Obiectele Callable trebuie apelate de metoda submit a unui ExecutorService
Metoda submit produce un obiect de tip Future parametrizat cu tipul
rezultatului specific returnat din task
Obiectul Future poate fi interogat cu metoda isDone() pentru a vedea daca
metoda call a produs rezultatul.
Metoda get() a obiectului Future obtine rezultatul produs de metoda call.
Daca rezultatul nu este disponibil, metoda get este de tip blocking (pana
cand rezultatul devine disponibil)

Cluj-Napoca - 26 mai 2021


Threaduri daemon
Un thread daemon furnizeaza un serviciu general programului care ruleaza
in background pe durata executiei programului
Intr-un program, cand toate threadurile non-daemon isi termina executia,
programul este terminat, JVM omorand toate threadurile daemon
Daca exista threaduri non-daemon care se executa, programul nu se
termina
Main este executat intr-o instanta non-daemon
Un thread se marcheaza ca si daemon inainte ca sa se inceapa executia
acestuia cu start
Daca un thread daemon creaza alte threaduri, acestea devin daemon la
randul lor

Cluj-Napoca - 26 mai 2021


Crearea unor interfete grafice responsive
Interfetele grafice trebuie sa raspunda rapid inputului utilizatorului chiar daca
acesta presupune calcule sofisticate si de lunga durata
Pentru a realiza un program care raspunde inputului utilizatorului, taskul de
lunga durata trebuie rulat in thread nou (metoda run)

Cluj-Napoca - 26 mai 2021


Prinderea exceptiilor
Daca apare o exceptie in metoda run, aceasta se va propaga pana la consola, in cazul
in care exceptia nu e rezolvata in run
Problema e rezolvata cu Executors
Exceptiile aruncate de metoda run nu pot fi prinse cu try-catch in jurul comenzii exec
a executorului
Prinderea unei exceptii aruncate de metoda run a unui thread
 Se implementeaza interfata Thread.UncaughtExceptionHandler, creandu-se o clasa handler
de exceptie
 Pentru threadul care ruleaza taskul, se asigneaza handlerul de exceptie cu metoda
setUncaughtExceptionHandler
 Aceasta operatie poate fi scrisa in medoa newThread a unui ThreadFactory, si apoi se pot
utiliza executorii
 Se poate asigna handlerul de exceptii implicit a clasei Thread cu
setDefaultUncaughtException

Cluj-Napoca - 26 mai 2021

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