You are on page 1of 52

Thread

multiprogramski,
multikorisnički,
multiprocesni sistemi
multithreading
Prioritet
sinhronizacija
batch obrada
 Batch obrada
Prvi kompjuteri….. obavljali su operacije samo jednu po
jednu. Svi su se programi izvršavali sekvencijalno, jedan
po jedan i svaki je zauzimao sve resurse računara.
To je efikasan način za postizanje maksimalne iskoristivosti
prvih (skupih) računara jer se gotovo sve CPU vreme
troši na stvarnu obradu.
batch obrada je nepovoljna ako programi koji traju nekoliko
sekundi moraju čekati na završetak programa od nekoliko
dana.
multiprogramski, multikorisnički,
multiprocesni sistemi
 U teoriji operativnih sistema postoji mnoštvo pojmova
(multiprogramski, multikorisnički, multiprocesni sistemi)
koji se, uz neznatne razlike, odnose na istu stvar -
mogućnost istovremenog izvršavanja većeg broja
programa.
 Ukoliko sistem ima veći broj procesora tada je moguće
istovremeno izvršavanje većeg broja procesa u pravom
smislu reči.
 Privid istovremenosti se može postići na taj način što
se procesor dodeljuje procesima naizmenično.
 Programi predstavljaju procese koji imaju svoj kontekst
unutar operativnog sistema.
 Prekidanje izvršavanja procesa kao i izbor procesa za
izvršavanje su pod potpunom kontrolom operativnog
sistema.
 Ovaj koncept je moguće nadograditi na taj način što se
pod kontrolom programa mogu kreirati procesi koji
predstavljaju autonomne celine samo unutar tog
programa.
 Takvi procesi se nazivaju laki procesi ili, niti.
Šta su niti
 Niti se često nazivaju laki procesi. Međutim, oni nisu
procesi. Nit je mali skup izvršnih instrukcija, koji se može
koristiti da izoluje zadatak iz procesa
 Više niti su efikasan način da se dobije paralelizam
hardvera i pruza interkciju korisnika sa svojim
aplikacijama.
Klasa thread.

Postoje dva načina da klasu pretvorimo u thread.


 klasu učinimo podklasom klase java.lang.Thread.

 implementiranje interfejsa java.lang.Runnable


Metode klase thread

metode koje se koriste za upravljanje threadovima:


public native synchronized void start()

public void run()

public final void stop()


 Metod start() priprema thread za izvršavanje.
 Metod run() obavlja zadatak namenjen threadu.
Thread se normalno završava kad on završi.
 Metod run() se ne poziva eksplicitno. On će,
nakon poziva metoda start() biti automatski
pozvan kad za to dođe vreme.
Kreiranje niti izvođenjem iz klase
Thread
 Pošto Java ne podržava višestruko izvođenje tada je moguće da
naša klasa bude izvedena iz klase Thread kao jedinog direktnog
prethodnika.
 Preklapanje metoda run koji je definisan u klasi Thread. Njegova
default implementacija je potpuno prazna tako da se klase koje
su izvedene iz klase Thread moraju uvesti svoju implementaciju.
 Metod run je u stvari telo niti - nakon kreiranja i startovanja niti
poziva se ovaj metod i u njemu se odigravaju sve akcije koje su
predviđene za tu nit
Metod run se u najvećem broju slučajeva sastoji od
petlje koja, dok je uslov za ostanak u njoj ispunjen,
obavlja najveći deo posla.
Primer
 dve klase - DveNiti i ProstaNit.
 Prva klasa služi samo za testiranje onoga što je u
drugoj klasi, jer samo kreira dve "proste niti" i
startuje ih.
 Druga klasa definiše samu nit obezbeđujući
konstruktor i preklapajući metod run. U
konstruktoru se definiše ime niti (pozivom
konstruktora osnovne klase)
 Metod run se sastoji od for petlje sa deset iteracija
u kojoj se štampa broj iteracije i ime niti nakon
čega se nit šalje na spavanje u trajanju od dve
sekunde (argument metoda sleep klase Thread je
u milisekundama).
 class DveNiti {
 public static void main (String[] args) {
 new ProstaNit("ja").start();
 new ProstaNit("ti").start();
 }
 }
 class ProstaNit extends Thread {
 public ProstaNit(String str) {
 super(str);
 }
  
  
 public void run(){
 for(int i=0; i<10; i++){
 System.out.println(i+" "+getName());
 try{
 sleep(2000);
 } catch (InterruptedException e) {}
 }
 System.out.println("uradio "+getName());
 }
 }
 0 ja
 0 ti
 1 ja
 1 ti
 2 ja
 2 ti
 3 ja
 3 ti
 ………….
 uradio ja
 uradio ti
Interfejs Runnable
 Omogućava upotrebu koncepta threadova u
klasama koje ne mogu biti podklase klase Thread.
Deklariše samo jednu metodu, run()
 public abstract void run()
 Ovaj način je nužan u situacijama kada klasa
koju pišemo mora biti izvedena iz neke druge
klase a ne klase Thread.
 Tipičan primer pri pisanju Appleta
 klasa Applet je osnovna klasa za klasu koju
pišemo tako da nam jedino ostaje da naša klasa
implementira interfejs Runnable
aplet koji prikazuje trenutno vreme
Objaš nje nje
Stanja u kojima se može naći
nit

yield()

new Thread() NOVA start()


NIT NE IZVRSAVA
IZVRSNA SE

stop() ili
stop() run() se završi stop()

MRTVA
NIT
Stanja u kojima se može naći
nit
 Nova nit (stanje NOVA NIT) nastaje pozivom
konstruktora klase Thread kao što i svaki drugi
objekat nastaje pozivom konstruktora svoje klase.
 Nova nit predstavlja jedan "prazan" objekat koji ne
zauzima nikakve resurse. Jedino što je moguće
uraditi sa ovakvim objektom jesu pozivi metoda
start() ili stop().
 Poziv bilo kog drugog metoda nad ovakvim
objektom će prouzrokovati
IllegalThreadStateException. !!!!! !!
 Kada se nova nit startuje, tj. kada se u stanju
NOVA NIT pozove metod start(), nit prelazi u
stanje IZVRSNA.
 Na poziv metoda start() alociraju se svi neophodni
resursi za izvršavanje niti i potom se poziva njen
metod run().
 Ovakvo ime za ovo stanje je namerno odabrano
da bi se signaliziralo da niti u ovom stanju ne
mora da bude dodeljen procesor, tj. da ona ne
mora da se izvršava.
 Da li će joj procesor biti dodeljen ne zavisi od nje
same već od izvršnog okruženja programa i
operativnog sistema koji upravljaju raspodelom
procesora. Ipak, ovo stanje je različito od stanja
NE IZVRSAVA SE i otuda njegovo ime.
Iz stanja IZVRSNA u stanje NE IZVRSAVA SE
nit može da pređe na poziv jednog od sledeća
tri metoda:
sleep - ovaj metod mora da pozove neko drugi
nad objektom niti.
suspend - i za ovaj metod važi gornji uslov,
wait - ovaj metod mora da pozove sama nit.

Pored toga nit iz stanja IZVRSNA u stanje NE


IZVRSAVA SE prelazi i ako se blokira na I/O.
 Ako je nit "poslata na spavanje" tada mora da
protekne vreme koje je specificirano kao argument
metoda sleep da bi se nit vratila u stanje IZVRSNA.
 Ako je nit suspendovana ona se onda u stanje
IZVRSNA vraća jedino pozivom metoda resume.
 Ako je nit blokirana metodom wait tada neka druga
nit mora pozvati metode notify ili notifyAll.
 I na kraju, ako je nit blokirana na I/O tada se taj I/O
mora završiti da bi se nit vratila u stanje IZVRSNA.
Prioritet niti
 Samo na sistemima sa više procesora procesi se mogu
izvršavati istovremeno.
 Na sistemima sa jednim procesorom to naravno nije
moguće. Kod njih je moguće konkurentno izvršavanje
procesa pri čemu se procesor naizmenično dodeljuje
procesima stvarajući na taj način iluziju istovremenosti.
 Krajnji rezultat je da se svi procesi zbirno izvrše za kraće
vreme nego kad bi se izvršavali sekvencijalno, jedan za
drugim.
 Java runtime definiše vrlo jednostavan algoritam
za upravljanje nitima koji je poznat pod nazivom
"šema sa fiksnim prioritetima".
 Svaka nit, dakle, ima svoj prioritet koji predstavlja
integer između MIN_PRIORITY i MAX_PRIORITY
,
konstante koje su definisane u klasi Thread.
 Veći integer viši je i prioritet niti.

 Kada se nit kreira ona nasleđuje prioritet niti koja


ju je kreirala a za eksplicitno postavljanje prioriteta
može da se koristi metod setPriority.
Pravila algoritma za
upravljanje nitima
 Uvek se izvršava nit sa najvećim prioritetom.
 Samo ako se ta nit suspenduje ili zaustavi,
šansu da se izvršava će dobiti neka nit sa
manjim prioritetom.
 Kada se bira nit za izvršavanje između većeg
broja niti sa istim prioritetom tada se to radi
na round-robin način.
Pravila algoritma za
upravljanje nitima
 Ako se u trenutku izvršavanja neke niti pojavi
nit koja ima veći prioritet tada ta nit odmah
preuzima procesor.
 Pozivom metoda yield() klase Thread nit
može da prepusti procesor nekoj drugoj niti
istog prioriteta. Pokušaj da se procesor na
ovaj način prepusti niti nižeg prioriteta se
ignoriše.
Sinhronizacija niti, monitori
 Niti mogu da dele podatke.
 Od trenutku preuzimanja procesora od
strane neke niti programer ne može da pravi
nikakve pretpostavke.
 Potrebni su mehanizmi koji obezbeđuju da ti
podaci ostanu konzistentni uprkos tome što
nad njima operiše veći broj niti.
Sinhronizacija niti
 Pretpostavimo da jedna nit (proizvođač)
proizvodi podatke koje druga nit (potrošač)
koristi.
 komunikacija između njih se obavlja preko
nekog bafera i neka je potrošaču potrebno da
svaki podatak koristi tačno jednom.
 Problem ?
Zbog (moguće) loše sinhronizacije između niti,
potrošač može jedan te isti podatak iskoristiti
veći broj puta a neke podatke možda
nijednom.
 Rešenje problema

Sinhronizacija niti
Klasa koja reprezentuje proizvođača

  
 class Proizvođac extends Thread {
 private Bafer baf;
  
 public Proizvođac(Bafer b) {
 baf = b;
 }
  
 public void run() {
 for (int i = 0; i < 10; i++) {
 baf.put(i);
 System.out.println("Proizvođac stavio: " + i);
 try {
 sleep((int)(Math.random() * 100));
 } catch (InterruptedException e) {}
 }
 }
 }
Klasa koja odgovara potrošaču

  
 class Potrosac extends Thread {
 private Bafer baf;
  
 public Potrosac(Bafer b) {
 baf= b;
 }
  
 public void run() {
 int value = 0;
 for (int i = 0; i < 10; i++) {
 value = baf.get();
 System.out.println("Potrosac uzeo: " + value);
 }
 }
 }
Bafer, preko koga proizvođač i
potrošač komuniciraju

  

 class Bafer {
 private int broj;
 private boolean uzmi = false;
  
 public synchronized int get(){while (uzmi ==
false) {
 try {
 wait();
 } catch (InterruptedException e) {
 }
 }
 uzmi = false;
 notifyAll();
 return broj;
 }
  
 public synchronized void put(int value) {
 while (moze == true) {
 try {
 wait();
 } catch (InterruptedException e) {
 }
 }
 broj = value;
 moze = true;
 notifyAll();
 }
 }
klasa koja kreira niti i započinje
program
  
 class Test {
 public static void main(String[] args) {
 Bafer b = new Bafer();
 Proizvođac pro = new Proizvođac(b);
 Potrosac pot = new Potrosac(b);
  
 pro.start();
 pot.start();
 }
 }
O pis
 Komunikacija između klasa Proizvođac i Potrosac
se obavlja preko jednog objekta klase Bafer.
 I proizvođač i potrošač se moraju inicijalizovati
jednim istim objektom klase Bafer, koji će obavljati
sinhronizaciju između njih.
 Klase Proizvođac i Potrosac implementiraju
metod run, a od podataka imaju samo referencu
na baferski objekat preko koga komuniciraju.
 Oba metoda se sastoje od for-do petlje u kojoj se
podaci, za slučaj proizvođača, stavljaju u bafer,
odnosno, za slučaj potrošača, uzimaju iz bafera
 Bafer je nešto komlikovanija klasa. Ona definiše
dva metoda :
get kojim se očitava sadržaj bafera i
put kojim se postavlja sadržaj bafera.
 Oba metoda imaju u svojoj deklaraciji ključnu reč
synchronized koja je zapravo ključ za ostvarivanje
sinhronizacije.
 Java implementira tzv. monitore - koncept koji je
prvi razradio Hoare još 1974. godine.
 Taj koncept se sastoji u tome da ako neko želi da
stekne ekskluzivno pravo pristupa nekom objektu
tada on dobija monitor nad tim objektom. Svako
drugi ko u tom trenutku pokušava da pristupi baš
tom objektu će biti blokiran i moraće da čeka sve
dok se monitor ne oslobodi.
 U programskom jeziku Java monitori nad
objektima se stiču pozivom njihovih
sinhronizovanih metoda, tj. metoda koji u svojoj
deklaraciji imaju ključnu reč synchronized.
 Svakom objektu se pridružuje po jedan monitor
tako da je sasvim prirodno da proizvođač i
potrošač u našem primeru moraju biti
inicijalizovani jednim istim baferom.
 Kompletna kontrola nad monitorima, njihovo
postavljanje i oslobađanje, vrši izvršno okruženje
programa, tj. Java runtime.
 Kada proizvođački objekat pozove metod put
nad svojim baferom on stiče monitor nad njim.
 Tada proizvođač ulazi u tzv. kritičnu sekciju u
kojoj se operiše nad deljenim podacima.
 Sve dok proizvođač ne oslobodi taj monitor
potrošačev eventualni poziv metoda get nad
baferom će proizvesti potrošačevo blokiranje.
 Proizvođač se mora zaštiti od postavljanja
vrednosti, a da prethodna nije bila očitana, kao što
se i potrošač mora zaštiti od višestrukog
očitavanja jedne iste vrednosti.
 Klasa Bafer definiše promenljivu uzmi koja
pokazuje da li se sadržaj može uzeti ili ne. Oba
metoda, i put i get, konsultuju ovu promenjlivu na
svom početku.
 Ukoliko dođe do problema tada se pozivom metoda
wait klase Object metod koji je trenutno aktivan
blokira. To prouzrokuje oslobađanje monitora tako da
ona druga nit može da nastavi bez problema.
 U slučaju da do ovakvog problema nije došlo sadržaj
bafera se postavlja, tj. očitava, vrednost varijable
uzmi se ažurira i poziva se metod notifyAll kojim se
sve blokirane niti stavljaju u red spremnih procesa.
 Ovaj poslednji poziv je veoma važan jer bez njega nit
koja je blokirana metodom wait nikada be bi mogla da
nastavi dalje.
 wait i notifyAll su metodi definisani u klasi Object i
mogu se pozvati samo od strane niti koja drži neki
monitor.
 Metod notifyAll budi sve niti koje čekaju na monitor pri
čemu se one stavljaju u red spremnih procesa. Kada
se monitor oslobodi jedna od njih (runtime će izabrati
jednu od njih) će ga preuzeti.
 Metod - notify - koji budi samo jednu nit (opet je na
runtime-u da odluči koju).
 rešenja zasnovana na upotrebi metoda notifyAll po
previlu elegantnija.
 Metod wait prouzrokuje da se nit koja ga pozove
blokira. Ta nit ostaje blokirana sve dok neka druga
nit ne pozove notifyAll (ili notify).
 Dve verzije metoda wait:
 wait(long timeout) koji čeka notifikaciju samo u
toku vremena koje se specificira u milisekundima i
 wait(long timeout, int nanos) koji je isti kao i
prethodni s tim što je vreme izraženo u mili i
nanosekundama

You might also like