Professional Documents
Culture Documents
09 Niti - Java
09 Niti - Java
Niti
Uvod
Nit kontrole (thread)
U veini tradicionalnih programskih jezika samo jedna nit kontrole Vienitno programiranje (multi-threading)
simultano izvravanje vie niti koje mogu deliti neke zajednike podatke konkurentno (ne pretpostavlja vie procesora) paralelno (pretpostavlja postojanje vie procesora koji omoguavaju stvarni paralelizam)
Vienitni program moe da se izvrava: Niti koje rade nad potpuno disjunktnim skupovima podataka su retke Ako dve niti mogu da modifikuju i itaju iste podatke
Rezultat neizvesnosti trke moe biti neispravno stanje nekog objekta Reenje problema neizvesnosti trke je u sinhronizaciji niti Sinhronizacija niti treba da obezbedi samo jednoj niti ekskluzivan pristup podacima u odreenom segmentu koda
Niti
08.04.2008.
Metod start aktivira novu nit kontrole (nit postaje spremna), a zatim se metod zavrava Okruenje (virtuelna maina) pokree run metod aktivne niti Standardni metod Thread.run() ne radi nita Metod run treba da bude redefinisan u korisnikoj klasi koja proiruje klasu Thread Kada se run metod niti zavri, nit zavrava izvrenje
Niti
08.04.2008.
Primer
Program sa dve niti, koje ispisuju "ping" i "PONG" razliitom frekvencijom:
class PingPong extends Thread { public String rec; int vreme; PingPong(String r, int v){ rec=r; vreme=v; } public void run(){ try{ for(;;){System.out.print(rec+" "); sleep(vreme);} } catch(InterruptedException e){ return; } } public static void main (String[] argumenti) { new PingPong("ping", 33).start(); // 1/30s new PingPong("PONG",100).start(); // 1/10s } }
Niti
08.04.2008.
Ovaj interfejs deklarie samo jedan metod: run Klasa Thread implementira Runnable Problem u prethodnom nainu kreiranja niti:
kada se izvodi iz klase Thread ne moe se izvoditi i iz neke druge projektovati klasu koja implementira interfejs Runnable kreirati objekat te klase proslediti objekat konstruktoru klase Thread
Niti
08.04.2008.
Primer
Isti primer periodinog ispisivanja " ping" i "PONG": class RunPingPong implements Runnable{ public String rec; int vreme; RunPingPong(String r, int v){rec=r; vreme=v;} public void run(){ try{for(;;){System.out.print(rec+" "); Thread.sleep(vreme);} } catch(InterruptedException e){ return; } } public static void main (String[] argumenti) { Runnable ping = new RunPingPong("ping", 33); Runnable pong = new RunPingPong("PONG", 100); new Thread(ping).start(); new Thread(pong).start(); } }
Niti
08.04.2008.
konstruie novu nit koja koristi metod run() objekta na koji pokazuje cilj
Niti
08.04.2008.
Niti
08.04.2008.
Zavravanje niti
Nit normalno zavrava izvrenje po povratku iz njenog metoda run Zastareli naini da se nit eksplicitno zaustavi
metod stop baca neprovereni izuzetak ThreadDeath ciljnoj niti program ne treba da hvata ThreadDeath hendler izuzetka na najviem nivou jednostavno ubija nit bez poruke otkljuavaju se brave koje je nit zakljuala
moe da dovede do trajnog blokiranja drugih niti koje ekaju na datim bravama
metodom aktivnog objekta postaviti uslov kraja nit u nekoj petlji metode run() ispituje uslov kraja ako nit utvrdi da je postavljen uslov kraja sama zavri metod run
Niti 08.04.2008.
suspendovati (metod suspend) reaktivirati (metod resume) zaustaviti (metod stop) korisnik pritiska taster "Prekid" za vreme neke vremenski zahtevne operacije
Primer: Thread obrada; //nit koja vri obradu public viod korisnikPritisnuoPrekid(){ obrada.suspend(); if (pitanjeDaNe("Zaista elite prekid?") obrada.stop(); else obrada.resume(); } Sva tri metoda su zastarela, ne preporuuje se njihovo korienje Nit se moe samosuspendovati (uspavati) pomou metode sleep()
10
Niti
08.04.2008.
Prekidanje niti
Niti se moe poslati signal prekida Metodi vezani za prekidanje niti:
alje signal prekida niti - postavlja joj status prekida (statiki) testira da li je tekua nit bila prekinuta i ponitava status prekida isInterrupted() testira da li je nit bila prekidana i ne menja status prekida interrupt() interrupted()
Ako se za nit koja je u blokiranom stanju (metode sleep, wait, join) pozove metod interrupt()
nit se deblokira (izlazi iz metode u kojoj se blokirala) prekinuta nit prima izuzetak InetrruptedException status prekida se ne postavlja
11
Niti
08.04.2008.
Po povratku iz join() garantovano je da je metod Racunanje.run() zavren Kada nit zavri, njen objekat ne nestaje, tako da se moe pristupiti njegovom stanju
12
Niti
08.04.2008.
Oblici join
public final void join() throws InterruptedException
13
Niti
08.04.2008.
2 korisnika trae od 2 alterska radnika banke da izvre uplatu na isti raun r Nit 1 Nit 2
s1=r.citajStanje(); s2=r.citajStanje(); s1+=uplata; s2+=uplata; r.promeniStanje(s1); r.promeniStanje(s2);
Samo druga uplata utie na konano stanje rauna (prva je izgubljena) Rezultat zavisi od sluajnog redosleda izvravanja pojedinih naredbi Program koji zavisi od sluajnog redosleda izvravanja naredbi je nekorektan
14
Niti
08.04.2008.
Sinhronizacija
Reenje neizvesnosti trke u Javi
Dok objektu pristupa jedna nit, objekat se zakljuava da sprei pristup druge niti Modifikator metoda synchronized aktivira mehanizam pristupa preko brave Kada nit zakljua objekat samo ta nit moe da pristupa objektu
ako jedna nit pozove sinhronizovan metod objekta ona dobija klju brave objekta druga nit koja pozove sinhronizovan metod istog objekta bie blokirana druga nit e se debloirati tek kada prethodna nit napusti sinhronizovani metod
Sinhronizacija obezbeuje uzajamno iskljuivanje niti nad zajednikim objektom Obrada ugnedenih poziva:
pozvan metod se izvrava, ali brava se ne otkljuava po povratku on se izvrava u jednoj niti dok objekat jo ne postoji pa mu druga nit ne moe pristupiti kroz metode se moe upravljati sinhronizacijom
Konstruktor ne treba da bude sinhronizovan iz sledeeg razloga Dodatni razlog protiv javnih podataka:
15
Niti
08.04.2008.
Primer sinhrionizacije
Klasa Racun je napisana da ivi u okruenju vie niti:
class Racun { private double stanje; public Racun(double pocetniDepozit) { stanje = pocetniDepozit; } public synchronized double citajStanje() { return stanje; } public synchronized void promeniStanje(double iznos) { stanje += iznos; } }
Sinhronizovan metod promeniStanje obavlja get-modify-set sekvencu Ako vie niti pristupaju objektu klase Racun konkurentno
16
Niti
08.04.2008.
jedna nit moe da izvrava sinhronizovani statiki dok druga moe da izvrava sinhronizovani nestatiki metod
17
Niti
08.04.2008.
Sinhronizacija i nasleivanje
Kada se redefinie metod u izvedenoj klasi:
osobina synchronized nee biti nasleena redefinisani metod moe biti sinhronizovan ili ne bez obzira na odgovarajui metod natklase
ako novi nesinhronizovani metod koristi super.m() objekat e biti zakljuan za vreme izvrenja metoda m() natklase
18
Niti
08.04.2008.
Sinhronizovane naredbe
Nain sinhronizacije koda bez pozivanja sinhronizovanog metoda nekog objekta Opti oblik:
synchronized (izraz) naredba //naredba je obino blok
Sinhronizovana naredba zakljuava objekat na koji upuuje rezultat izraz Kada se dobije brava, sinhronizovana naredba se izvrava kao da je sinhronizovani metod Primer:
public static void abs(int [] niz) { synchronized (niz) { for (int i=0; i<niz.length; i++) {if (niz[i]<0) niz[i]=-niz[i];} } }
ako bismo eleli sinhronizaciju finije granularnosti (iskljuivanje nad pojedinim elementima)
naredbu synchronized bi premestili ispred if
19
Niti
08.04.2008.
elimo da u okruenju sa vie niti koristimo klasu koja je ve projektovana za sekvencijalno izvrenje u jednoj niti (ima nesinhronizovane metode) kreirati izvedenu klasu sa sinhronizovanim redefinisanim metodama i prosleivati pozive koristei super koristiti sinhronizovanu naredbu za pristup objektu jer ne dozvoljava da se zaboravi sinhronizacija naredbe za pristup
Dva reenja:
20
Niti
08.04.2008.
21
Niti
08.04.2008.
22
Niti
08.04.2008.
23
Niti
08.04.2008.
24
Niti
08.04.2008.
Rasporeivanje niti
Nit najvieg prioriteta e se izvravati i sve niti tog prioriteta e dobiti procesorsko vreme Niti nieg prioriteta:
garantovano se izvravaju samo kada su niti vieg prioriteta blokirane mogu se izvravati i inae, ali se ne moe raunati sa tim
Nit je blokirana ako je uspavana ili izvrava funkciju ije je napredovanje blokirano Prioritete treba koristiti samo da se utie na politiku rasporeivanja iz razloga efikasnosti Korektnost algoritma ne sme biti zasnovana na prioritetima
25
Niti
08.04.2008.
Prioriteti
Inicijalno, nit ima prioritet niti koja ju je kreirala Prioritet se moe promeniti koristei:
Vrednosti su izmeu:
Prioritet niti koja se izvrava se moe menjati u bilo kom trenutku Metod getPriority() vraa tekui prioritet niti
26
Niti
08.04.2008.
Primer
public class Prioriteti extends Thread{ int id; int prior; long vreme; static long pocetnoVreme; Prioriteti(int id){this.id=id;} public void run(){ prior=getPriority(); for (long i=0; i<100000000;i++){} Izlaz: 0: 1, 3.426219379s vreme=System.nanoTime()-pocetnoVreme; 1: 2, 3.239005143s } 2: 3, 1.771297724s public static void main(String[] args){ 3: 4, 2.073052552s int n =5; Prioriteti[] niti = new Prioriteti[n]; 4: 5, 0.586774067s for (int i=0; i<niti.length; i++) (niti[i]=new Prioriteti(i)).setPriority(i+1); pocetnoVreme = System.nanoTime(); for (int i=0; i<niti.length; i++) niti[i].start(); for (int i=0; i<niti.length; i++){ try{niti[i].join(); }catch (InterruptedException e){} System.out.println(niti[i].id+": +niti[i].prior+","+niti[i].vreme/1.0e9+"s"); } } }
27
Niti
08.04.2008.
uspavljuje tekue izvravanu nit za barem specificirani broj milisekundi ako se pozove iz sinhronizovane metode, ne otkljuava brau za vreme spavanja
tekua nit predaje procesor da omogui drugim nitima da dobiju procesor; nit koja e se aktivirati moe biti i ona koja je pozvala yield, jer moe biti ba najvieg prioriteta
28
Niti
08.04.2008.
29
Niti
08.04.2008.
30
Niti
08.04.2008.
Do blokiranja dolazi kada svaki objekat eka na bravu drugog Situacija za uzajamno blokiranje:
objekat X ima sinhronizovan metod koji poziva sinhronizovan metod objekta Y objekat Y ima sinhronizovan metod koji poziva sinhronizovan metod objekta X postoji scenario kada e oba objekta ekati na onaj drugi da bi dobili bravu Nit x: Nit y: x.m1() y.m2() y.m1() x.m2()
Java ne detektuje niti spreava uzajamno blokiranje Programer je odgovoran da izbegne uzajamno blokiranje U gornjem sluaju isti redosled pristupanja bravama bi reio problem
31
Niti
08.04.2008.
ta se deava sa njima po povratku iz main? korisnike niti nastavljaju i aplikacija se ne zavrava demonske niti se zavravaju ako nema korisnikih niti, pa se i aplikacija zavrava
Demonstvo se nasleuje od niti koja kreira novu nit Demonstvo se ne moe promeniti nakon to se nit startuje Ako se pokua promena bie baen izuzetak IllegalStateException
32
Niti
08.04.2008.
33
Niti
08.04.2008.
volatile
Bez sinhronizacije, vie niti mogu modifikovati/itati isto polje simultano Takvo polje treba markirati kao nepostojano (volatile) Primer:
vrednost se kontinuirano prikazuje iz niti koja vri samo prikazivanje, a moe se promeniti iz drugih niti kroz nesinhronizovane metode vrednost = 5; for (;;){ ekran.prikazi(vrednost); Thread.sleep(1000); } ako se vrednost ne markira kao volatile prevodilac moe optimizirati kod i koristiti konstantu 5 umesto promenljive
34
Niti
08.04.2008.
mogu da modifikuju druge niti u grupi i grupama koje su sadrane u toj grupi ne mogu da modifikuju niti izvan vlastite grupe i sadranih grupa
Svaka nit pripada nekoj grupi niti Grupa se moe specificirati u konstruktoru niti Podrazumevana grupa je grupa kreatora niti Kada se nit zavri, objekat niti se uklanja iz njene grupe Objekat ThreadGroup koji je pridruen niti
Metod getThreadGroup() klase Thread vraa grupu kojoj nit pripada Metod checkAccess() klase Thread proverava pravo modifikovanja neke niti
ako nit nema pravo modifikovanja druge niti metod e baciti SecurityException demonska grupa se unitava kada ostane prazna Niti
35
08.04.2008.
Pokuaj postavljanja prioriteta niti na vii bie redukovan bez obavetenja Primer (ograniavanje prioriteta drugim nitima):
static public void ogranicavanjePrioriteta(Thread t){ ThreadGroup g = t.getThreadGroup(); t.setPriority(Thread.MAX_PRIORITY); g.setMaxPriority(t.getPriority()-1); } novi maksimum grupe se postavlja na prethodni maksimum grupe 1, ne na Thread.MAX_PRIORITY-1
36
Niti
08.04.2008.
Neuhvaen izuzetak
Neuhvaen izuzetak - uncaughtException Kada nit (t) zavrava zbog neuhvaenog izuzetka (e) pokree se metod
public void uncaughtException(Thread nit, Throwable i)
pokree metod uncaughtException roditeljske grupe, ako ova postoji koristi metod Throwable.printStackTrace ako ne postoji roditeljska grupa
Ovaj metod se moe redefinisati u vlastitoj grupi niti Promena podrazumevanog rukovaoca neuhvaenog izuzetka za neku nit:
setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler i) interfejs Thread.UncaughtExceptionHandler sadri metod: void uncaughtException(Thread nit, Throwable i)
37
Niti
08.04.2008.
kreira novu grupu tipa ThreadGroup zadatog imena; roditelj e biti grupa tekue niti kreira novu grupu sa eksplicitno specificiranom roditeljskom grupom vraa ime grupe niti vraa roditeljsku grupu ili null ako ova ne postoji postavlja status demonstva grupe niti vraa informaciju o demonstvu grupe niti postavlja maksimalni prioritet za grupu niti vraa maksimalni prioritet grupe niti Niti 08.04.2008.
public ThreadGroup(ThreadGroup parent, String name) public final String getName() public final ThreadGroup getParent() public final void setDaemon(boolean daemon) public final boolean isDaemon() public final synchronized void setMaxPriority(int maxPri) public final int getMaxPriority()
38
proverava da li je grupa niti roditelj datoj grupi niti g, ili je u pitanju sama grupa g; grupa je deo same sebe
baca SecurityException ako tekuoj niti dopouteno da modifikuje grupu iji se metod poziva, inae nita unitava grupu niti; grupa se ne moe unititi ako u njoj ima niti (baca se IllegalThreadStateException)
zaustavlja sve niti u datoj grupi i svim njenim podgrupama suspenduje sve niti u datoj grupi i svim njenim podgrupama reaktivira sve niti u datoj grupi i svim njenim podgrupama vraa procenu broja aktivnih niti u grupi ukljuujui niti u svim podgrupama Niti 08.04.2008.
public final synchronized void suspend() public final synchronized void resume() public synchronized int activeCount()
39
popunjava niz threads referencama na svaku aktivnu nit u grupi, sve do veliine niza; ako je rekurz == true sve niti iz hijerarhije e biti ukljuene ekvivalent za enumerate(niti,true) vraa broj postojeih grupa niti popunjava niz grp referencama na aktivne podgrupe niti ekvivalent za enumerate(grp,true)
public synchronized int activeGroupCount() public int enumerate(ThreadGroup[] grp,boolean rekurz) public int enumerate(ThreadGroup[] grp) public String toString()
vraa string koji reprezentuje grupu niti, ukljuujui ime i prioritet prikazuje rekurzivno grupu niti na System.out
40
Niti
08.04.2008.
vraa broj aktivnih niti u tekuoj grupi niti vraa vrednost enumerate(niti) tekue grupe niti
41
Niti
08.04.2008.