Your SlideShare is downloading. ×
Programmazione concorrente in Java (vecchio modello)
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Programmazione concorrente in Java (vecchio modello)

4,637
views

Published on

Un tutorial base sui thread in Java

Un tutorial base sui thread in Java

Published in: Technology, Business

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
4,637
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
122
Comments
0
Likes
0
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Concurrent Programming in Java Guida alle API e descrizione del modello di concorrenza in Java Autore: Davide Carboni <davide.carboni@crs4.it> © Copyright 2000-2001 CRS4 (www.crs4.it)
  • 2. Concorrenza Fare più di una cosa per volta Esempio: un web browser fa il download di una pagina HTML, suona un’ audioclip, attende un input da tastiera, visualizza nella barra di stato il bitrate ect..
  • 3. Ma è vera concorrenza ? In alcuni sistemi differenti task possono essere assegnati a differenti CPU In altri una singola CPU divide il proprio tempo fra i vari task , la sensazione è quella di esecuzione simultanea.
  • 4. Quali Applicazioni Number Crunching I/O processing Simulation GUI Embedded Systems
  • 5. Clusters Ogni macchina esegue una unità di esecuzione concorrente Facile da amministrare ma svantaggioso per la difficoltà di condividere risorse e passare messaggi
  • 6. Multi Processing Il processo è un’astrazione che fornisce il SO Ogni processo tipicamente rappresenta un programma durante l’esecuzione Ogni processo gestisce il suo spazio dati che non condivide La comunicazione tra processi avviene tramite IPC, pipes ...
  • 7. Multi Threading Un processo può avere uno o più thread, ognuno dei quali è ancora una unità di esecuzione indipendente. I thread appartenenti allo stesso processo condividono la memoria, i file ed altre risorse le loro azioni sono sincronizzate grazie ai lock e al meccanismo wait,notify
  • 8. Multi Threading I thread possono essere schedulati dal kernel nei sistemi in cui il kernel li supporta (linux, windows, …)
  • 9. Multi Threading Un processo può gestire il suo multithreading internamente anche se il kernel non supporta i thread. Questo viene fatto da processi come la JVM, SQL server etc… La JVM fornisce un costrutto concorrente anche se il SO è “monotaskoso”
  • 10. I Thread in Java Java fornisce diversi strumenti per la programmazione concorrente: java.lang.Thread class java.lang.Object class java.lang.Runnable interface synchronized keyword
  • 11. I Thread in Java (FAQ) Come parte un Thread ? Quando un Thread è in esecuzione quale codice esegue ? In quali/quanti stati può essere un Thread ? Come e perché i Thread cambiano il loro stato ?
  • 12. Come parte un Thread ? Un Thread è un’istanza della classe java.lang.Thread o di una sua sottoclasse ma inizia la sua esecuzione SOLO quando viene invocato il suo metodo start() esempio: Thread t=new MyThread(Qualcosa); t.start();
  • 13. Cosa fa il metodo start() Il metodo start() registra l’istanza del Thread in un “pezzo di software” chiamato Thread Scheduler Il Thread Scheduler può essere interno alla JVM oppure esterno (servizio del SO) Il Thread Scheduler decide quale Thread è in esecuzione su una data CPU e in dato momento.
  • 14. Priorità Ogni thread ha la sua priorità che va da 1 (bassa) a 10 (alta) t.getPriority() restituisce l’attuale priorità del Thread t t.setPriority(8) impone a 8 la priorità del Thread t
  • 15. Ancora l’esempio esempio: Thread t=new MyThread(Qualcosa); t.start(); a questo punto ci sono almeno 2 Thread, uno è il main che ha eseguito le due linee sopra e l’altro è t
  • 16. Quando un Thread è in esecuzione quale codice esegue ? La risposta è: Il codice contenuto nel suo metodo run () Il metodo run( ) della classe java.lang.Thread è vuoto quindi i nostri Thread faranno l’overriding
  • 17. Esempio:overriding di run( ) public class CounterThread extends Thread { public void run() { for(int i=1;i<=10;i++) System.out.println(“conto “+i); } }
  • 18. Esempio:lancio il Thread CounterThread c=new CounterThread; c.start( ); // non uso c.run( ) Se usassi c.run( ) otterrei l’esecuzione immediata di run( ) senza inserire c nello scheduler
  • 19. Perché questo approccio non è soddisfacente ? A causa dell’ereditarietà singola la nostra classe thread non può estendere altre classi. Questo è un grosso problema nel design di architetture complesse.
  • 20. java.lang.Runnable La classe java.lang.Thread ha un secondo costruttore : public Thread(Runnable eseguibile) L’interfaccia Runnable ha il solo metodo public void run();
  • 21. java.lang.Runnable Grazie a Runnable posso costruire architetture più complesse public class Derived extends Base implements Runnable{ public void run( ) { faiqualcosainmultithreading;} public int f(int x){ ...} public Object g(byte [] x){ ...} }
  • 22. java.lang.Runnable Derived d=new Derived( … ); Thread t=new Thread(d); t.start( ); d.f(x); //non c’entra con i thread
  • 23. La morte dei Thread I thread “muoiono” quando il metodo run ( ) ritorna In realtà sono dei non-morti perché pur non essendo più eseguibili sono ancora degli oggetti Java validi e tutti i loro metodi possono essere ancora invocati
  • 24. Gerarchia di classi Class Object Runnable Class Base Class Derived Class Thread
  • 25. La morte dei Thread Valgono perciò 2 regole: 1. Un thread il cui metodo run( ) ritorna NON può essere più “restartato” 2. Se l’istanza del thread non viene Gcollected i suoi metodi possono essere invocati
  • 26. La morte dei Thread Non è una buona strategia quella di creare, usare e buttare via dei thread perché la costruzione e lo scheduling di un thread è un’operazione onerosa. Per ovviare a questo esistono tecniche di Thread Pooling, ossia mi tengo un’insieme di Thread pronti all’uso
  • 27. Esempio: un web server in java public class Server { int port=9000; Socket socket=null; ServerSocket sock_serv=null; public void boot(int port) { …} … [snip] }
  • 28. Esempio: un web server in java public void boot(int port) throws Exception { this.port=port; sock_serv=new ServerSocket(port); MyThread aThread=null; while(true) { socket=sock_serv.accept(); aThread=new MyThread(socket); aThread.start(); } }
  • 29. Esempio: un web server in java public class MyThread extends Thread { Socket socket=null; MyThread(Socket s) { socket=s; } public void run() { …[implementation]… } }
  • 30. Esempio: un web server in java public void run(){ try{ PrintWriter writer=new PrintWriter(socket.getOutputStream(),true); BufferedReader reader= new BufferedReader( new InputStreamReader(socket.getInputStream())); … [snip] …
  • 31. Esempio: un web server in java public void run(){ … [snip] … String input=reader.readLine(); if(input.startsWith(quot;GETquot;)) { writer.println(quot;<html><body><p><h1>quot;); writer.println(quot;CIAO A TUTTIquot;); writer.println(quot;</h1></p></body></html>quot;); } socket.close(); return; }//end of try block catch(Exception e){ … } }
  • 32. In quali/quanti stati può essere un Thread ? Running Ready-to-run Suspended, Blocked, Sleeping (not ready) Monitor states (sync,wait/notify sequence) Dead
  • 33. In quali/quanti stati può essere un Thread ? running Monitor suspended sleeping blocked states Ready-to-run
  • 34. Transizioni di stato t.yield( ) causa al running Thread t il passaggio da running a ready-to-run in questo modo un Thread diverso da t ha la Ready-to-run possibilità immediata di passare allo stato running
  • 35. Transizioni di stato suspend() running suspend( ) e suspended resume( ) sono deprecati in java1.2 Ready-to-run resume()
  • 36. Transizioni di stato Thread.sleep(long) sleep(long) causa al thread che running lo invoca il passaggio allo stato sleeping sleeping E’ un sistema di Ready-to-run Time expires or interrupted timing ma non è precisissimo
  • 37. Transizioni di stato Alcuni metodi Blocking causano il blocco running method del thread invocante, questo blocked capita quando di mezzo c’è un device che non risponde Ready-to-run Interruption subito come un’ or change in blocking interfaccia di rete device
  • 38. Blocco di un Thread aSocket=new Socket(“www.unica.it”,80); InputStream i=aSocket.getInputStream( ); int b = i.read(); // qui ci possiamo bloccare Se la “rete” non è pronta a fornirci il int richiesto il thread in esecuzione si blocca !!
  • 39. Perché bisogna sincronizzare Cattivo Esempio class Pari{ private int n=0; public int next(){ n++; n++; return n; } }
  • 40. Perché bisogna sincronizzare Thread A Thread B – read 0 – write 1 – read 1 – write 2 – read 2 – read 2 – write 3 – write 3 – return 3 – return 3
  • 41. Codice sincronizzato Ogni istanza di java.lang.Object o di una sua sottoclasse possiede un LOCK Un valore primitivo (int,long,…) non possiede nessun LOCK Un array di tipi primitivi o Object possiede un LOCK
  • 42. synchronized synchronized(a) Solo il thread che { acquisisce il LOCK istruz_1; di a può eseguire il istruz_2; blocco. … Gli altri thread in istruz_k; competizione per il } LOCK si bloccano in uno stato detto di seeking
  • 43. synchronized L’approccio precedente consente di sincronizzare un blocco di codice di un oggetto O con un LOCK di un altro oggetto a Potente possibilità ma pericoloso !
  • 44. Lo stato seeking lock Enter synchronized code running seeking scheduled Lock obtained ready to run
  • 45. synchronized Object f( ) { synchronized(this){ ...codice... } } EQUIVALE synchronized Object f( ) { ...codice... }
  • 46. synchronized Class S{ public synchronized void f( ) { … } public synchronized void g( ) { … } public void h( ) { … } } invocare f() e g() su istanze di S ci costringe a competere per il lock, però possiamo invocare liberamente h( )
  • 47. synchronized O = new S( ); O.f( ); //aspetto che il LOCK sia mio … ; //al ritorno di f( ) ho rilasciato il LOCK O.h( ); // la eseguo e basta O.g( ); // aspetto che il LOCK sia mio … ; //ho già rilasciato il LOCK
  • 48. Atomicità Un oggetto si dice atomico se: tutti i metodi sono sincronizzati non ci sono attributi pubblici o altre violazioni dell’incapsulamento tutti i metodi sono finiti (senza loop infiniti) lo stato dell’oggetto è costruito in modo consistente lo stato è consistente sia alla fine che all’inizio di ogni metodo anche in presenza di eccezioni
  • 49. Thread Safe Le classi di oggetti che implementano l’atomicità sono thread safe, ossia il loro stato non può essere corrotto dall’esecuzione di più thread simultaneamente
  • 50. Deadlock Anche se un oggetto atomico è thread safe i thread che lo usano possono finire in uno stato detto Deadlock (abbraccio mortale) lock lock O1 O2
  • 51. Monitor Un monitor è un oggetto che può bloccare e risvegliare thread In Java ogni oggetto dotato di codice synchronized è un monitor
  • 52. Monitor: ma a che servono? Attraverso le primitive wait e notify possiamo coordinare le attivita’ di 2 o piu’ thread
  • 53. Esempio di wait, notify public class SpaceProvider implements net.jini.discovery.DiscoveryListener { [snip] … private JavaSpace space; … [snip] … public synchronized JavaSpace getSpace(String category) throws Exception { … } [snip] … public synchronized void discovered(DiscoveryEvent e) { …. } }
  • 54. Esempio di wait, notify public synchronized JavaSpace getSpace(String category) ... { if(space==null){ LookupDiscovery ld=new LookupDiscovery(…); ld.addDiscoveryListener(this); wait(60000); Questo thread si blocca } in monitor-state if(space == null) { throw new Exception (quot;No space found”); } return space; }
  • 55. Esempio di wait, notify public synchronized void discovered(DiscoveryEvent e) { ServiceRegistrar reggie=e.getRegistrars()[0]; … [snip] … try{ space=(JavaSpace)reggie.lookup(…); if(space!=null) { notify(); A questo punto l’altro thread passa } in ready-to run } catch(Exception ex){ ex.printStackTrace(); } }
  • 56. Esempio di wait, notify public synchronized JavaSpace getSpace(String category) ... { if(space==null){ LookupDiscovery ld=new LookupDiscovery(…); ld.addDiscoveryListener(this); wait(60000); } if(space == null) { throw new Exception (quot;No space found”); } return space; }
  • 57. Esempio di wait, notify Ricapitolando Un monitor e’ un qualsiasi oggetto che possiede del codice synchronized
  • 58. Esempio di wait, notify Ricapitolando wait causa al thread che la esegue la cessione del lock ed il blocco in monitor-state. Se il thread che esegue wait non detiene il lock viene lanciata un’eccezione
  • 59. Esempio di wait, notify Ricapitolando notify causa al thread che la esegue la cessione del lock notify risveglia un thread che ha eseguito wait sul monitor Il thread risvegliato passa dallo stato monitor-state allo stato ready-to-run
  • 60. Altri modi per coordinare I thread wait e notify coordinano le attivita’ dei thread usando un lock come elemento di coordinazione join coordina un thread sull’esecuzione di un’altro thread
  • 61. Altri modi per coordinare i thread public static void main(String[] args) …{ System.out.println(quot;main thread:messaggio 1quot;); Runnable r1= new Runnable(){ public void run(){ for (int i= 0; i < 10; i++) { System.out.println(quot;r1 thread:messaggio quot;+ i); try{Thread.sleep(1000);} catch (Exception e) {e.printStackTrace();} } } }; …[snip]
  • 62. Altri modi per coordinare I thread …[snip] Thread t1= new Thread(r1); t1.start(); System.out.println(quot;main thread:messaggio 2quot;); t1.join(); System.out.println(quot;main thread:messaggio 3quot;); }
  • 63. Altri modi per coordinare I thread Output: main thread:messaggio 1 r1 thread:messaggio 0 main thread:messaggio 2 r1 thread:messaggio 1 r1 thread:messaggio 2 r1 thread:messaggio 3 r1 thread:messaggio 4 r1 thread:messaggio 5 r1 thread:messaggio 6 r1 thread:messaggio 7 r1 thread:messaggio 8 r1 thread:messaggio 9 main thread:messaggio 3
  • 64. Altri modi per coordinare I thread main() Main thread messaggio 1 t1.start() r1 thread messaggio 0 Main thread messaggio 2 t1.join() r1 thread messaggio 1 …. r1 thread messaggio 9 t Main thread messaggio 3
  • 65. Limiti del modello Operazioni deprecate stop(), suspend(), resume() Mancanza del back off da seeking-lock Denial-of-service in caso di synchronized(obj) Block structured Locking
  • 66. Operazioni deprecate stop() Questa operazione e’ thread-unsafe perche' costringe il thread a terminare rilasciando i lock degli oggetti. Gli oggetti rilasciati possono finire in uno stato inconsistente.
  • 67. Operazioni deprecate suspend(),resume() Sospendere un thread e’ pericoloso perche’ il thread sospeso mantiene i lock degli oggetti senza procedere.
  • 68. Operazioni deprecate suspend(),resume() Esempio: 2 Thread T1 e T2 T1 possiede il lock O T2 sospende T1 T2 cerca di eseguire un blocco sincronizzato su O T2 e’ bloccato in seeking-lock su O T1 non rilascera’ mai O perche’ e’ sospeso T1 e T2 sono entrambi bloccati, in assenza di un terzo thread il sistema resta bloccato.
  • 69. Mancanza del back off da seeking-lock Un thread T che cerca di eseguire codice sincronizzato su un lock O viene messo in competizione per l’acquisizione di O e NON puo’ tirarsi indietro
  • 70. Denial-of-service Qualunque metodo puo sincronizzare parte del suo codice su un qualunque oggetto O di cui abbia visibilita’ tramite synchronized(O) Un meccanismo di accesso controllato ai lock potrebbe ridurre la possibilita; di denial-of-service
  • 71. Block structured Locking Lo scope di acquisizione rilascio e’ strettamente a livello di blocco o di metodo, non e’ possibile acquisire il lock in un metodo M1 e rilasciarlo in un metodo M2.
  • 72. Bibliografia Thinking in Java, Bruce Eckel, Prentice Hall Concurrent Programming in Java, Doug Lea, Addison Wesley The complete Java 2 certification guide, S.Roberts et al., Sybex The Java Language Specifications, J. Gosling et al., Addison Wesley
  • 73. Q&A

×