Download presentation
Presentation is loading. Please wait.
1
Procesare paralela in Java
12/1/2017 Curs 8 Procesare paralela in Java
2
Arhitecturi Paralele
3
Clasificare arhitecturi paralele
Clasificarea Flyn SISD - conventional SIMD - calcul vectorial MISD - scalcul sistolic MIMD – cazul general
4
SISD : Von Neuman Instructiuni Procesor Date Intrare Date Iesire
5
Arhitectura MISD B C A Flux de date de Iesire Flux de date de Intrare
Instructiuni A Flux de date de Iesire Procesor A B C Instructiuni B Flux de Instructiuni C Flux de date de Intrare
6
Architectura SIMD Ci<= Ai * Bi A B C Flux de Instructiuni Flux de
Procesor A B C Date de Intrare A Flux de Date de Iesire A Flux de Date de Iesire B Flux de Date de Intrare B Flux de Date de Iesire C Flux de Date de Intrare C Ci<= Ai * Bi
7
Architectura MIMD A B C Flux de Instructiuni A Flux de Instructiuni B
Instructiuni C Flux de Date de Iesire A Flux de Date de Intrare A Procesor A Flux de Date de Iesire B Flux de Date de Intrare B Procesor B Flux de Date de Iesire C Flux de Date de Intrare C Procesor C
8
Masina MIMD cu memorie comuna
Procesor A Procesor B Procesor C MEMORIE MAGISTRALA MEMORIE MAGISTRALA MEMORIE MAGISTRALA Sistem de Memorie Globala
9
MIMD cu memorie distribuita
Canal Comunicatie Canal Comunicatie Procesor A Procesor B Procesor C MEMORIE MAGISTRALA MEMORIE MAGISTRALA MEMORIE MAGISTRALA Memorie Sistem A Memorie Sistem B Memorie Sistem C
10
Nivele de paralelism
11
Nivele de Paralelism Granularitate cod Entitate Cod Granularitate mare
(nivel task) Program Granularitate medie (nivel control) Functie (thread) Granularitate fina (nivel date) Bucla Granularitate foarte fina (alegeri multiple ) Cu suport hard Task i-l Task i Task i+1 func1 ( ) { .... } func2 ( ) { .... } func3 ( ) { .... } a ( 0 ) =.. b ( 0 ) =.. a ( 1 )=.. b ( 1 )=.. a ( 2 )=.. b ( 2 )=.. + x Load
12
Paralelism la nivel de procese
13
Procesul clasic Memorie comuna Mentinuta de kernel procese processe
Stiva Stiva Memorie COMUNA, segmente, pipes, Fisiere deschise sau mapate in memorie Date Date Text Text Memorie comuna Mentinuta de kernel procese processe
14
Definirea/Instantierea unor procese Exemple de relatii de precedenta
15
Procese cu unul sau mai multe fire interne de executie
Proces cu un singur fir de executie Proces cu mai multe fire de executie Fire de executie Thread-uri Flux unic de instructiuni Spatiu de adrese COMUN pt fire Al procesului Flux multiplu de instructiuni
16
Thread-uri
17
Ce sunt firele de executie?
Un fir de executie este o portiune de cod executabil care se poate executa in paralel (concurent) cu alte fire de executie) Registri Context Hardware/ software Cuvant stare Program Counter executare
18
Thread light (“proces usor”)
STIVA FIRULUI Memorie Comuna DATELE FIRULUI TEXTUL FIRULUI Thread light (“proces usor”) Un fir de executie peste o zona mica continua de memorie care este primit de la (si din) procesul parinte
19
Exemplu Thread in Linux
void *func ( ) { /* define local data */ /* function code */ thr_exit(exit_value); } main ( ) thread_t tid; int exit_value; thread_create (0, 0, func (), NULL, &tid); thread_join (tid, 0, &exit_value);
20
Paralelism in procese Date a b r1 c d r2
int add (int a, int b, int & result) // corpul int sub(int a, int b, int & result) Date Procesor a b r1 c d r2 IS1 add pthread t1, t2; pthread-create(&t1, add, a,b, & r1); pthread-create(&t2, sub, c,d, & r2); pthread-par (2, t1, t2); Processor IS2 sub
21
Paralelism date do “ dn/2 dn2/+1 dn sort( int *array, int count)
//...... Procesor do “ dn/2 dn2/+1 dn Sortare pthread-t, thread1, thread2; “ pthread-create(& thread1, sort, array, N/2); pthread-create(& thread2, sort, array, N/2); pthread-par(2, thread1, thread2); IS Procesor Sortare
22
De ce thread-uri? Proces cu un singur fir de executie: apeluri blocante, executie secventiala Cu automat finit (bazat pe eveniment) apeluri neblocante si paralelism
23
Sistem de operare
24
Thread-uri utilizator
12/1/2017 Thread-uri utilizator Thread-urile sunt gestionate de o biblioteca de thread-uri
25
Thread-uri la nivel kernel
12/1/2017 Kernel-ul este constient de existenta thread-uri
26
Procese “usoare” (Light-weight-LWP)
12/1/2017 Procese “usoare” (Light-weight-LWP) Presupun maparea maparea mai multor LWP peste un proces real (greu - heavy-weight)
27
(UNIX, VMS, MVS, NT, OS/2 etc.)
Sisteme Multitasking Proces Spatiu Utilizator Kernel Structura Procesului UNIX Hardware (UNIX, VMS, MVS, NT, OS/2 etc.)
28
Sisteme Multitasking Procese P1 P2 P3 P4 kernel Hardware
Fiecare proces este independent kernel Hardware
29
Procese Multithread T1’s SP T3’sPC T1’sPC T2’sPC T1’s SP Cod
Utilizator Date globale T2’s SP Structura Procesului Kernel
30
Maparea thread-urilor
1:1 DEC, NT, OS/1, AIX. IRIX M:1 HP-UNIX M:M 2-level
31
Modelul pe doua nivele al SunOS
Proces Traditional Proc 1 Proc 2 Proc 3 Proc 4 Proc 5 Utilizator LWP-uri Thread-uri Kernel Kernel Hardware Procesoare
32
Paralelism la nivel de thread-uri
33
Multithreading – Mono procesor
Concureta Vs Paralelism Concurenta P1 CPU P2 P3 timp
34
Multithreading - Multiprocesor
Concurenta Vs Paralelism CPU P1 CPU P2 CPU P3 timp
35
Thread-uri la nivel user
Model de lucru Thread-uri la nivel user Procesoare virtuale Procesoare fizice Planificare nivel user (User) Planificare nivel Kernel (Kernel)
36
Architectura generala a modelului bazat pe thread-uri
Ascunde detaliile arhitecturii masinii Mapeaza thread-urile user peste cele native ale kernel Memoria procesului parinte este vazuta in comun de thread-uri
37
Modele de programare folosind thread-uri
1. master/slave Peer 3. pipeline
38
Modelul master slave Resurse Program sclavi Fisiere Baze Date Stapan
taskX Baze Date Stapan taskY main ( ) Input (Stream) Disc-uri taskZ Dispozitive Speciale
39
Modelul peer Resurse Input (static) Program Sclavi Fisiere Baze Date
12/1/2017 Program Resurse Sclavi Input (static) Fisiere taskX Baze Date taskY Disc-uri taskZ Dispozitive Speciale
40
Pipeline de thread-uri
Program Filtru Thread-uri Nivel 1 Nivel 2 Nivel 3 Input (Stream) Fisiere Baze date Disc-uri Dispozitive Speciale Fisiere Baze date Disc-uri Dispozitive Speciale Fisiere Baze date Disc-uri Dispozitive Speciale Resurse
41
Observatii privind utilizarea thread-urilor
Daca toate operatiile sunt cu mai consumatoare de procesor nu este recomandat sa se lucreze pe thread-uri Desi crearea este simpla totusi foloseste ea insasi niste resurse Thread-urile prea simple (5 linii) nu sunt eficiente
42
Detalii fire de executie
43
Cai de creare a unui thread in Java
class MyThread extends Thread { public void run() // corpul thread ce trebuie executat } MyThread thr1 = new MyThread(); thr1.start();
44
Se creaza o clasa care implementeaza interfata Runnable
class ClassName implements Runnable { ..... public void run() // corpul thread ce trebuie executat } ClassName myObject = new ClassName(); Thread thr1 = new Thread( myObject ); thr1.start();
45
Exemplul 2 class ThreadDemo implements Runnable { ThreadDemo()
{Thread ct = Thread.currentThread(); System.out.println("Current Thread: "+ct); Thread t = new Thread(this,"Demo Thread"); t.start(); try { Thread.sleep(3000); } catch(InterruptedException e) { System.out.println("Interrupted."); } System.out.println("Exiting mainthread."); }
46
public void run() { try { for(int i=5; i>0; i--) { System.out.println(" " + i); Thread.sleep(1000); } } catch(InterruptedException e) { System.out.println("Child interrupted."); } System.out.println("Exiting child thread."); public static void main(String args[]) new ThreadDemo();
47
Gestiunea thread-ului curent
class CurrentThreadDemo { public static void main(String arg[]) { Thread ct = Thread.currentThread(); ct.setName( "My Thread" ); System.out.println("Current Thread : "+ct); try { for(int i=5; i>0; i--) { System.out.println(" " + i); Thread.sleep(1000); }
48
Current Thread : Thread[My Thread,5,main]
catch(InterruptedException e) { System.out.println("Interrupted.") } Run: Current Thread : Thread[My Thread,5,main] 5 4 3 2 1
49
Ciclul de viata al unui thread
50
Runnable Thread-ul este lansat în execuţie prin apelul metodei start() din clasa Thread.
Not Runnable - se poate ajunge în această stare dacă:
51
Dead În această stare se ajunge când firul şi-a terminat execuţia. Metoda isAlive() returnează: true, dacă firul de execuţie a fost pornit şi nu a fost oprit (este în starea Runnable sau Not Runnable) false, dacă firul de execuţie este fie în starea New Thread, fie în starea Dead.
52
Cazurile în care un fir de execuţie poate ajunge din starea Not Runnable în starea Runnable
Dacă a fost apelată metoda sleep(), atunci firul execuţie ajunge în starea Runnable după scurgerea intervalului de timp specificat. Dacă a fost apelată metoda wait(), atunci un alt fir de execuţie trebuie să-l informeze dacă acea condiţie este îndeplinită sau nu (folosind metodele notify() şi notifyAll() din clasa Object).
53
Oprirea temporară a unui fir de execuţie
public static void sleep(long millis) throws InterruptedException public static void sleep(long millis,int nanos) throws InterruptedException De exemplu: try { // se face o pauza de o secunda Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace();}
54
Terminarea unui fir de execuţie
Pentru ca un fir de execuţie să se termine trebuie ca metoda run() să-şi termine execuţia. Există două metode pentru terminarea unui fir de execuţie: Metoda run() îşi termină execuţia în mod natural: dacă avem instrucţiuni cu timp de execuţie finit Daca avem bucle finite.
55
Fire de execuţie de tip „daemon”
Un „daemon” reprezintă un fir de execuţie care se termină automat la terminarea aplicaţiei. De obicei firele „daemon” pun la dispoziţia celorlalte fire de execuţie anumite servicii.
56
Proceselor/firelor de executie
Planificarea Proceselor/firelor de executie
57
Alternarea seventelor de calcul cu rafalele (“burst”) de instructiuni de intrare iesire
58
Planificatorul CPU Selecteaza dintre procesele active in memorie pe cele care sunt gata a fi executate si rezerva procesorul pentru unul din ele (secvential pur) Deciziile de planificare pot aparea atunci cand un proces: 1. Trece din starea de executie in starea de asteptare 2. Trece din starea de executie in starea de gata de executie 3. Trece din starea de asteptare in starea de gata de executie 4. Se termina
59
Distribuitorul/Selectorul de procese - Dispatcher
Acest modul da controlul procesorului catre procesul selectat de catre planificatorul pe termen scurt si implica Schimbarea contextului Trecerea in mod utilizator Saltul catre locatia corespunzatoare din programul utilizatorului pentru a-l reporni Intarzierea selectorului – timpul necesar acestuia pentrua a opri un proces si a-l porni pe urmatorul
60
Criterii pentru realizarea planificarii
Utilizarea procesor Max Incarcare - Throughput – Max Turnaround time – Min Timp de asteptare – Min Timp de raspuns – ) Min
61
Planificare de tip primul venit primul servit (FCFS)
Proces Timp operatii i/o P1 24 P2 3 P3 3 Sa presupunem ca procesele ajung in urmatoarea ordine: P1 , P2 , P3 Atunci diagrama Gantt pentru planificare este: P1 P2 P3 24 27 30
62
FCFS Dca procesele ajung in ordinea P2 , P3 , P1 atunci vom avea urmatoarea diagrama Gatt a planificarii lor P1 P3 P2 6 3 30
63
Cea mai scurta sarcina este prima (SJF)
Se asociaza fiecarui process lungimea urmatorului set de operatii de I/O care il va efectua (CPU burst). Aceste lungimi sunt folosite pentru a planifica procesul cu cel mai scurt timp Exista doua abordari: Nepreemptiva preemptiva
64
Exemplu de SJF nepreemptiv
Proces Timp sosire Timp operatii I/O P P P P SJF (non-preemptiv) P1 P3 P2 7 3 16 P4 8 12
65
Exemplu de SJF preemptiv
Proces Timp de aparitie Timp pentru i/o P P P P SJF (preemptiv) P1 P3 P2 4 2 11 P4 5 7 16
66
Planificare bazata pe prioritati
Un numar al prioritatii este asociat la fiecare proces Procesorul va fi dat procesului cu prioritatea cea mai mare (adica cel mai mic numar). Si in acest caz procesul de planificare poate fi: Preemptiv nepreemptiv Problema Starvation Solutie Aging
67
Round Robin (RR) Fiecare proces primeste o mica unitate din timpul procesorului (cuanta de timp – time quantum), de obicei durata acesteia este intre 10 si 100 milliseconde. Daca exista n procese in aceasta coada si cuanta de timp este q, atunci fiecare proces va avea acces la 1/n din timpul procesorului in bucati de cel mult q unitati de timp o data. Rezulta ca nici un proces nu va astepta mai mult de (n-1)q unitati de timp. Performanta q este mare FIFO q este mica q trebuie sa fie mare tinand insa cont de comutarea contextului altfel supraincarcarea obtinuta va fi prea mare
68
Exemplu de RR cu cuanta de 20
Proces Timp pentru i/o P1 53 P2 17 P3 68 P4 24 Diagrama Gantt asociata va fi: P1 P2 P3 P4 20 37 57 77 97 117 121 134 154 162
69
Cuanta de timp si timpul de de comutare a contextului
70
Timpul de executie a unui proces variaza functie de cuanta de timp
71
Cozi multinivel Coada “gata de executie” este formata din doua cozi separate foreground – interactiva background – fundal (batch) Fiecare coada are propriul ei algoritm de planificare foreground – RR background – FCFS Planificarea trebuie realizata intre cozi Planificare cu prioritate fixa Cu cuante de timp
72
Planificarea cozilor multinivel
73
Coada de raspuns (feedback) multinivel
Un proces poate fi mutat ntre cozi diferite (de exemplu “imbatranirea” poate fi implenentata in aceasta maniera Un planificator pentru coada de raspuns multinivel (multilevel-feedback-queue) este definit de utmatorii parametri Numarul cozilor Algoritmi de planificare pentru fiecare coada Metodele folosite pentru a determina cand se creste prioritatea unui proces Metodele folosite pentru a determina cand se scade prioritatea unui proces Metodele folosite pentru a determina in care coada va intra un proces care trebuie tratat
74
Exemplu de coada de raspuns multinivel
Fie trei cozi: Q0 – cu cuanta de timp 8 milisecunde Q1 – cu cuanta de timp de 16 milisecunde Q2 – FCFS
75
Planificarea in Linux Se folosesc doi algoritmi Time-sharing Real-time
Bazat pe prioritati de credit (Prioritized credit-based) – Creditul este scazut atunci cand apare o intrerupere de timp Cand creditul = 0, se alege alt proces Cand toate procesele au creditul = 0, se reincepe procesul de creditare Real-time Soft real-time Daca este conform standardului Posix.1b vom avea doua categorii FCFS si RR Procesul cu cea mai mare prioritate este primul executat
76
Planificarea thread-urilor
Locala atunci cand ninlioteca de thread-uri va decide Globala atunci cand decide kernel-ul
77
Planificarea thread-urilor in Java
JVM foloseste o politica de planificarea preemptiva bazata pe prioritati JVM va planifica un thread spre executare atunci cand: Thread-ul care este in executie curenta va parasi starea Runnable Un thread cu o prioritate mai mare intra in starea Runnable
78
Time-Slicing Deoarece planificarea pe cuante nu este asigurata de JVM trebuie folosita metoda yield() while (true) { // fa un calcul intensiv computational . . . Thread.yield(); }
79
Prioritatile thread-urilor
Prioritate tip Thread.MIN_PRIORITY prioritate minima Thread.MAX_PRIORITY prioritate maxima Thread.NORM_PRIORITY prioritate implicita Prioritatile pot fi schimbate folosind metoda setPriority() De ex setPriority(Thread.NORM_PRIORITY + 2);
80
Exemplu Prioritati thread
class Clicker implements Runnable { int click = 0; private Thread t; private boolean running = true; public Clicker(int p) { t = new Thread(this); t.setPriority(p); } public void run() { while(running) click++; } public void start() { t.start(); } public void stop() { running = false; }
81
Exemplu Prioritati thread
class HiLoPri { public static void main(String args[]) {Thread.currentThread().setPriority(Thread.MAX_PRIORITY); Clicker Hi = new Clicker(Thread.NORM_PRIORITY+2); Clicker Lo = new Clicker(Thread.NORM_PRIORITY-2); Lo.start(); Hi.start(); try Thread.sleep(10000); } catch (Exception e) { }
82
Lo. stop(); Hi. stop(); System. out. println(Lo. click + " vs. " + Hi
Lo.stop(); Hi.stop(); System.out.println(Lo.click + " vs. " + Hi.click); } Run1: (on Solaris) 0 vs Run2: (Window 95) vs
83
Problema inversiunii prioritatilor in cazul sincronizarii
Fie un proces L de prioritate scazuta si un proces H de prioritate crescuta. Ambele au acces la o resursa comuna unica (adica se permite numai acces mutual exclusiv)
84
Solutia pentru inversia prioritatii
Protocol de mostenire a prioritatilor Daca thread-ul t1 incearca sa achizitioneze un lock care este detinut de un thread de prioritate scazuta t2, atunci se va creste temporar prioritatea lui t2 la nivelul celei detinute de t1 in timpul in care t2 mentine lock-ul Protocol cu simularea limitarii prioritatii (Highest locker) Unui monitor I se da o prioritate atunci cand este creat. Aceasta este cea mai mare prioritate pe care un thread care incearca sa intre in zona monitorizata o poate avea O data ce thread-ul intra in zona sincronizata prioritatea lui este crescuta la cea a monitorului.
85
Coerenta datelor Ce facem daca mai multi vor sa scrie simultan aceasi valoare? Cea mai simpla solutie:excluziunea mutuala
86
Variabile pentru sincronizare in memoria comuna
Proces 1 Proces 2 Variabila pentru sinchronizare Memorie Comuna S S S S Thread
87
Lock Definitie O entitate care poate fi detinuta de un singur thread la un moment dat Proprietati Reprezinta o forma/tip de sincronizare Este folosita pentru a intari/realiza excluziunea mutuala Thread-urile pot achizitiona/elibera un lock
88
Obiecte sincronizate in Java
TOATE obiectele java furnizeaza (pt ca detin) un lock Se aplica cuvantul cheie synchronized asupra obiect Se obtine excluziunea mutuala pentru secventa din bloc Exemplu Object x = new Object(); void foo() { synchronized(x) { ... } bloc
89
Metode sincronizate in Java
Si metodele Java furnizeaza lock-uri Se aplica cuvantul cheie synchronized la metoda Se sincronizeaza pe un obiect (implicit) apeland metoda Example synchronized void foo() { …cod… } // este echivalenta cu void foo() { synchronized (this) { …cod… } } bloc
90
Sincronizarea accesului la campuri “mutable”
12/1/2017 Sincronizarea accesului la campuri “mutable” Acestea sunt de fapt camputile care permit modificarea continutului. Intr-un mediu parallel ( multi thread) accesarea unei variabile commune necesita coordonare explicita intre cei care scri si cei care citesc datorita problemei coerentei datelor. Procesul de coordonare in acest caz se numeste sincronizare.
91
12/1/2017 Exemplu import java.util.Date; public final class MutablePlanet { public MutablePlanet(int aId, String aName, Date aDateOfDiscovery) fId = aId; fName = aName; fDateOfDiscovery = new Date(aDateOfDiscovery.getTime()); }
92
12/1/2017 public synchronized int getId() {return fId;} public synchronized void setId(int aNewId) { fId = aNewId; } public synchronized String getName() { return fName; } public synchronized void setName(String aNewName) { fName = aNewName; } public synchronized Date getDateOfDiscovery() { return new Date(fDateOfDiscovery.getTime()); } public synchronized void setDateOfDiscovery( Date aNewDiscoveryDate) { fDateOfDiscovery.setTime(aNewDiscoveryDate.getTime()); }
93
12/1/2017 private int fId; private String fName; private Date fDateOfDiscovery; // }
94
Indicatii pentru crearea unei clase imutabila
12/1/2017 Indicatii pentru crearea unei clase imutabila Asigurati ca clasa nu poate fi suprascrisa folosind final sau fabric static impreuna cu constructori private Campurile clasei trebuie sa fie private si final Nu furnizati nici o metoda care poate schimba starea unui obiect in nici un fel (nu nu mai setere si getere nimic)
95
Exemplu import java.util.Date; public final class Planet {
12/1/2017 Exemplu import java.util.Date; public final class Planet { public Planet (double aMass, String aName, Date aDateOfDiscovery) fMass = aMass; fName = aName; fDateOfDiscovery = new Date(aDateOfDiscovery.getTime()); } public double getMass() { return fMass;
96
12/1/2017 public String getName() { return fName; } // public Date getDateOfDiscovery() { //not ok // return fDateOfDiscovery; // } public Date getDateOfDiscovery() {//ok return new Date(fDateOfDiscovery.getTime()); private final double fMass; private final String fName; private final Date fDateOfDiscovery;
97
12/1/2017 Lock In cazul lock-ului intrinsec operatiunea de lock va fi efectuata automat de catre Java (in spatele scenei). Utilizarea synchronized este asociata cu doua tipuri de lock intrinsec Un “lock pe instanta” care este atasat unui singur obiect Un “lock static” atasata unei clase
98
12/1/2017 In mod similar preluare controlului unui lock static va impedica celelalte thread-uri sa apeleze o metoda sincronizata static DANU NU va bloca apelul metodelor nesincronizate sau a instantelor de metoda sincronizate Lock-ul static poate fi obtinut in afara header-ului metodei in doua moduri synchronized(Blah.class),folosind clasa literal synchronized(this.getClass()), daca un obiect este disponibil
99
Exista doua categorii de operatii asupra unui obiect:
Cu apel unic: Cu apel multiplu Exista mai multe situatii care trebuie analizate pentru a decide utilizarea lock-ului lock-never apelantul nu are nevoie nici o data sa obtina un lock extern inainte de a efectua orice tip de operatie.
100
lock-always – apelantul are nevoie intotdeauna sa obtina un lock extern inainte de efectuarea oricarei operatii. lock-sometimes – apelantul are nevoie cate o data sa obtina un lock extern inainte de a fectua unele operatii. Instantele sunt mutable iar implementarea clasei efectuare intern majoritatea sincronizarilor. lock-hostile – operatiile nu pot fi effectuate correct (safe) intr-un mediu multi-thread chiar daca se obtine tot tipul lock-ul extern.
101
Sincronizarea la nivel de sectiuni
Controlul executiei
102
Hazard de curse - Data Race
x = y = 0 Thread 1 Thread-urile pornesc Thread 2 x = 1 y = 1 j = y i = x Se poate sa avem ca rezultat i = 0 and j = 0?
103
Raspuns: DA! x = y = 0 Thread 1 Thread 2 Thread-urile pornesc x = 1
j = y i = x
104
Cum se poate intampla asa ceva?
Compilatorul poate reordona instructiunile Sau sa mentina variabilele in registri Procesorul le poate reordona Modelul de memorie folosit este proiectat sa suporte otimizari agresive (cu relaxarea conditiilor) Poate include optimizari neimplementate in general
105
Sincronizarea Se foloseste cand
Trebuie delimitat un bloc care trebuie sa aiba executie atomica (neintrerupta) de alt thread Introduce un punct de sincronizare a informatiei/comunicatiei intre thread-uri Obs Implica totusi o supraincarcare (mica) in timpul executiei.
106
Exemplu de operatiune neatomica
public class OperNeAtomica implements Runnable { static int x = 0; public void run() { int tmp = x; x = tmp+1; } public static void main(String[] args) for (int i = 0; i < 3; i++) new Thread(new OperNeAtomica ()).start(); System.out.println(x); }
107
Probleme la sincronizare
Utilizarea acelasi lock pentru a furniza excluderea mutuala Asigurarea tranzactiilor atomice Evitarea deadlock=ului
108
Utilizarea acelasi lock
Lock comun Lock separat Exemplu void run() { Object o = new Object(); // diferit pentru fiecare thread synchronized(o) { … // sunt sanse sa apara data race }
109
Tranzactie atomica Problema potentiala Exemplu synchronized(lock) {
int tmp = x; x = tmp; }
110
Utillizarea sincronizarii
public class OperNeAtomica implements Runnable { static int x = 0; static Object lock = new Object(); public void run() { int tmp; synchronized(lock) { tmp = x; }; synchronized(lock) { x = tmp+1; } }
111
Evitarea blocajului reciproc
In general este bine a se evita executia unor operatii consumatoare de timp intr-o zona de lock (cand se mentine controlul acestuia) Ce poate dura? Diverse… Aparitia altui lock Poate aparea blocaj reciproc (deadlock)
112
Exemplu Deadlock Thread1() { synchronized(a) synchronized(b) … ceva }
113
Exemplul 2 de deadlock void moveMoney(Account a, Account b, int amount) {synchronized(a) {synchronized(b) { a.debit(amount); b.credit(amount); } Thread1() { moveMoney(a,b,10); } Thread2() { moveMoney(b,a,100); }
114
Abstract Data Type – Buffer
115
Implementare Buffer public class Buffer {
private LinkedList objects = new LinkedList(); public synchronized add( Object x ) { objects.add(x); } public synchronized Object remove() { while (objects.isEmpty()) { ; return objects.removeFirst();
116
Eliminare Deadlock public class Buffer { private Object [] myObjects;
private int numberObjects = 0; public synchronized add( Object x ) { objects.add(x); } public Object remove() { while (true) { synchronize(this) { if (!objects.isEmpty()) { return objects.removeFirst(); } }
117
Metodele Wait & Notify wait() Apelata de un obiect notifyAll()
118
Utilizarea Wait si NotifyAll
public class Buffer { private LinkedList objects = new LinkedList(); public synchronized add( Object x ) { objects.add(x); this.notifyAll(); } public synchronized Object remove() { while (objects.isEmpty()) { this.wait(); } return objects.removeFirst();
119
Codul devine public class Buffer
{ private LinkedList objects = new LinkedList(); public synchronized add( Object x ) {objects.add(x); this.notifyAll(); } public synchronized Object remove() { while (objects.isEmpty()) { try { this.wait(); } catch (InterruptedException e) {} } return objects.removeFirst();
120
Ce este un thread pool O colectie de thread-uri care sunt create simultan ( de exemplu cand un server porneste) NU este necesar ca serverul sa reeze cate un thread pe masura ce cererile de la clienti apar IN loc serverul poate folosi un thread care a fost deja creat si care fie este liber fie se va elibera in curand
121
De ce avem nevoie de thread pools
Imbunatatesc utilizarea resurselor atentie crearea unui nou thread induce totusi o suprancarcare care nu poate neglijata Folosirea lor permite aplicatiilor sa isi controleze complet utilizarea thread-urilor interne
122
Utilizarea in servere Thread pools sunt importante in psecial pentru aplicatiile de tip client server Deoarece procesarea fiecarui task individual dureaza putin iasr numarul de cereri este mare Serverele nu trebuie sa consume mai mult timp si resurse pentru crearea si distrugerea thread-urilor decat pentru deservirea clientilor
123
Implementarea evidenta
12/1/2017 Implementarea evidenta Fie un pool de thread Fiecare task cere la pornire un thread si il returneaza pool-ului dupa ce si-a terminat treaba Care este problema aici Modelul “Synchronized” - clientul asteapta pana cand serverul ii satisface cererile
124
Implementarea evidenta …. nu e cea mai buna
Cand pool-ul este gol threadu-l emitent de job trebuie sa astepte ca un thread sa fie disponibil De obicei se doreste evitarea blocarii acestui thread Un server ar putea dori sa efectueze unele actiuni cand vin prea multe cereri
125
Toate thread-urile worker asteapta pentru a primi treaba
O solutie posibila Fiecare thread se uita dupa cereri (tasks) in coada wait() Coada Task-uri Thread-uri worker Daca Q este gol Toate thread-urile worker asteapta pentru a primi treaba
126
O solutie posibila Task Coada Task-uri Thread-uri worker
Model “A-synchronized” “Lanseaza si uita ” Numarul de thread-uri worker este Fix. Atunci cand un task este introdus in coada Este apelat un notify
127
O solutie posibila Task Coada Task-uri Thread-uri Worker
notify() Task Coada Task-uri Thread-uri Worker Numarul de thread-uri este fix Atunci cand un task este inserat In coada va fi apelat notify
128
Thread Pool Implementation
public class TaskManager { LinkedList taskQueue = new LinkedList(); List threads = new LinkedList(); public TaskManager(int numThreads) {for(int i=0; i<numThreads; ++i) {Thread worker = new Worker(taskQueue); threads.add(worker); worker.start(); } public void execute(Runnable task) {synchronized(taskQueue) { taskQueue.addLast(task); taskQueue.notify(); }
129
Thread Pool Implementation
public class Worker extends Thread { LinkedList taskQueue = null; public Worker(LinkedList queue) { taskQueue = queue; } public void run() { Runnable task = null; while (true) { synchronized (taskQueue) { while (taskQueue.isEmpty()) { try {taskQueue.wait();} catch (InterruptedException ignored) {} } task = (Runnable) taskQueue.removeFirst(); task.run();
130
Riscuri in folosirea Thread Pools
Thread-urile pot avea scapari Sa se blocheze astepand terminarea unei operatii de i/o De exemplu clientul poate oprin interactiunea cu un socket fara a-l inchide corespunzator
131
Dimensiunea pool-ului
Fiecare thread consuma resurse: memore, efort pentru management etc. Un pool mare poate conduce la infometare Task-urile care vin asteapta un thread liber
132
Tratarea a unui numar prea mare de cereri la un server multithtread
Nu se adauga la coada de procesare toate cererile (se ignora sau se trimite un mesaj de eroare) Se folosesc cateva dimensiuni predefinite pentru pool conform tipului de incarcare al serverului ( dar ete bine ca sa nu schimbam prea des dimensiunea pool-ului)
133
Calculul dimensiunii pool
Telul principale este: ca procesarea sa continue chiar daca se astepata ca operatii lente de I/O sa se termine Fie urmatoarele variabile: WT = timpul mediu estimat ST= timpul mediu de rezolvare estimat pentru o cerere (fara timpii de asteptare) Atunci: WT/ST+1 thread-uri vor fi de ajuns ca sa mentina procesorul la incarcare maxima
134
12/1/2017 Clasa Executor Are doua metode statice pentru crearea de pool-uri de thread-uri ExecutorService newFixedThreadPool(int nThreads) Poate crea un pool de dimensiune fixa ExecutorService newCachedThreadPool() Creaza noi thread-uri functie de necesitati Noile thread-uri sunt adaugate la pool si reciclate ExecutorService has an execute method void execute(Runnable command)
135
{ private final ServerSocket serverSocket;
class NetworkService { private final ServerSocket serverSocket; private final ExecutorService pool; public NetworkService(int port, int poolSize) throws IOException { serverSocket = new ServerSocket(port); pool = Executors.newFixedThreadPool(poolSize); } public void serve() { try for (;;) { pool.execute(new Handler(serverSocket.accept()));} } catch (IOException ex) { pool.shutdown();
136
{ private final Socket socket; Handler(Socket socket)
class Handler implements Runnable { private final Socket socket; Handler(Socket socket) { this.socket = socket; } public void run() { // citeste si deserveste cererea} }
137
Referinte thread-life-cycle
138
After …. this course
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.