|
JSem: 5.3 |
Stati di un thread Il metodo isAlive() ritorna true se il thread è Runnable o Not Runnable e ritorna false se il thread è New Thread (sostanzialmente in gestazione ma non ancora nato) o Dead. Se isAlive() ritorna true (risp. false) non è possibile distinguere tra Runnable e Not Runnable (risp. New Thread e Dead). Un thread può quindi passare più volte dallo stato Not Runnable allo stato Runnable; inoltre siccome la CPU, a un dato momento, può eseguire un unico thread, un thread Runnable passerà più volte da uno stato di "pronto" a uno stato di "esecuzione" (e viceversa). Priorità Due parole per chiarire l'ultima frase. I vari sistemi operativi affrontano il problema del multithreading essenzialmente in due modi: Il metodo "preemptive" (solaris, unix) è più prevedibile ma presenta l'inconveniente che un thread con alta priorità potrebbe eseguirsi in eterno, impedendo l'esecuzione di altri threads. La spartizione del tempo (Windows, Macintosh) è meno prevedibile, ma impedisce a threads troppo egoisti di impossesarsi di tutte le risorse. Il runtime di Java abbiamo detto è piuttosto del tipo "preemptive", ma questo non è del tutto vero perchè si riserva comunque il diritto di eseguire threads con priorità più basse se questo può evitare il "congelamento" (starvation) del programma. Morale: non fare troppo affidamento nel codice sulle priorità tra threads! Per illustrare quanto detto finora ecco un piccolo programma (preso dal "Java tutorial" Campione-Walrath (Addison-Wesley 1998)) che si propone di fare una gara tra due threads. Iniziamo col definire la classe dei threads:
La classe si chiama SelfishRunner (selfish = egoista) perchè il metodo run() contiene un blocco while e il thread, quando in esecuzione, non lascerà volentieri la CPU finchè il suo ciclo while non sarà terminato. Passiamo adesso al programma:
Qui si creano due threads con uguale priorità; se il sistema operativo segue il metodo del "time slicing" benchè i threads siano (visto il loro metodo run) un pò egoisti, l'output non dovrebbe essere del tutto squilibrato: Thread #0, tick = 50000 Thread #0, tick = 100000 Thread #1, tick = 50000 Thread #1, tick = 100000 Thread #1, tick = 150000 Thread #1, tick = 200000 Thread #1, tick = 250000 Thread #1, tick = 300000 Thread #1, tick = 350000 Thread #1, tick = 400000 Thread #0, tick = 150000 Thread #0, tick = 200000 Thread #0, tick = 250000 Thread #0, tick = 300000 Thread #0, tick = 350000 Thread #0, tick = 400000(output ottenuto con Windows 98) Se invece si cambiano le priorità, per esempio runners[i].setPriority(i+2); nella sesta riga della classe Gara, allora non c'è più gara: Thread #1, tick = 50000 Thread #1, tick = 100000 Thread #1, tick = 150000 Thread #1, tick = 200000 Thread #1, tick = 250000 Thread #1, tick = 300000 Thread #1, tick = 350000 Thread #1, tick = 400000 Thread #0, tick = 50000 Thread #0, tick = 100000 Thread #0, tick = 150000 Thread #0, tick = 200000 Thread #0, tick = 250000 Thread #0, tick = 300000 Thread #0, tick = 350000 Thread #0, tick = 400000 Infatti il thread #1 ha priorità 3 mentre il thread #0 ha priorità 2. Con un sistema che non addotta il "time-slicing" si dovrebbe ottenere questo output (con thread#0 al posto di thread#1) anche quando i threads hanno la stessa priorità. |
next content previous