Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Clustering di applicazioni Java SE  con Terracotta Guido Anselmi [email_address] Java User Group Milano http://www.jugmila...
Sommario <ul><li>Cos'è Terracotta ed a cosa serve
Ambiti di utilizzo
Le basi del clustering in Terracotta
Object Roots e Clustered Objects
Virtual Heap
Thread coordination e Locks
Esempi di sincronizzazione/coordinamento tra JVM diverse </li></ul>
Casi d'uso e definizioni Terracotta is a transparent clustering service for Java applications I tipici casi d'uso di Terra...
Overview Terracotta è un  servizio  di  clustering   trasparente . “ Trasparente ” è riferito al linguaggio Java, in cui i...
POJO Clustering-Instrumented classes Affinchè Terracotta possa effettivamente operare sul nostro codice ( bytecode  in rea...
POJO Clustering - Roots Un oggetto definito come root è l'elemento radice di un grafo di oggetti clusterizzati.  Qualunque...
POJO Clustering - Roots I fields dichiarati come root assumono una speciale semantica 1) La prima volta che un field root ...
POJO Clustering - Roots Ma come fa terracotta a trasformare in maniera trasparente una variabile d'istanza o statica in un...
POJO Clustering - Locks Quando diversi threads accedono concorrentemente gli stessi dati sullo heap, speciali precauzioni ...
POJO Clustering - Locks Cosa deve cambiare  nel codice quando mutua escliusione e collaborazione assumono una valenza a li...
POJO Clustering - Locks <locks> <autolock> <lock-level>write</lock-level> <method-expression>void HelloWorld.method(..)</m...
POJO Clustering - Locks A differenza di Java, i lock di Terracotta hanno diversi livelli: •   write •  synchronous-write •...
Esempio1 Immaginiamo di avere un insieme di threads il cui compito consiste unicamente nell'estrarre dei Job da un coda co...
Esempio1 La coda è evidentemente un oggetto condiviso, quindi va protetta dall'accesso concorrente da parte di thread diff...
Esempio1 Dove Job è un'interfaccia che potremmo implementare nel modo seguente public interface Job { public static final ...
Esempio1 Ed infine il terzo attore, il thread che fa il lavoro sporco, prelevandolo dalla coda. public class SimpleWorker ...
Esempio1 Vogliamo adesso testare il nostro piccolo sistema, costruendo una coda contenente 10 jobs e lanciando 30 diversi ...
Esempio1 public class SimpleMain { JobQueue queue = new SimpleJobQueue ( 10 ); CyclicBarrier barrier = new CyclicBarrier (...
Esempio1 Ed infine questa è la configurazione di Terracotta per ottenere quanto descritto <? xml   version = &quot;1.0&quo...
Esempio1 < application > < dso > < instrumented-classes > < include > < class-expression > *..* </ class-expression > </ i...
Esempio1 A questo punto lanciamo il server Trerracotta ed infine, mandiamo in esecuzione il nostro esempio set /p base=Ple...
Esempio1 Prendiamo in esame le prime linee di codice significative JobQueue queue = new SimpleJobQueue ( 10 ); CyclicBarri...
Esempio1 Primo main esegue: JobQueue queue = new SimpleJobQueue ( 10 ); La variabile queue è dichiarata come root, Terraco...
Esempio1 JVM  X augmented bytecode bytecode
Esempio2 Il nostro primo esempio ha diversi difetti In particolare la gestione della sincronizzazione è un evidente collo ...
Esempio2 Proviamo a fare di meglio, diminuendo le contese. In particolare, poiché nel nostro esempio semplificato ciascun ...
Esempio2 Adesso i nostri worker cambiano la propria politica di accesso alla coda public   void  run() { int  status; Job ...
Esempio2 Il file di configurazione di Terracotta non deve essere rivoluzionato, anzi viene addirittura semplificato. < app...
Esempio3 Complichiamo ancora lo scenario; finora i nostri threads lavorano in esclusione; il primo che guadagna l'accesso ...
Condition Le Condition, a differenza dei classici metodi di Object, consentono al singolo oggetto di comportarsi come se a...
Condition I metodi offerti da Condition sono analoghi a quelli di Object: void await()  sospende il thread corrente finqua...
Esempio3 Per prima cosa il Job cambia definizione: public   interface  CollaborativeJob { public   static   final   int   ...
Esempio3 Anche la coda necessita di essere modificata, aggiungendo le strutture necessarie ad implementare i meccanismi di...
Esempio3 Ed infine il nuovo worker public   void  run() { CollaborativeJob job; queue.getLockAt(index).lock(); job = queue...
Esempio3 Come cambia la configurazione di Terracotta? In nessun modo! Terracotta onora la semantica di java.util.concurren...
Struttura esempi
Upcoming SlideShare
Loading in …5
×

Terracotta JUG Milano

736 views

Published on

Presentazione del 27 01 2011

  • Be the first to comment

  • Be the first to like this

Terracotta JUG Milano

  1. 1. Clustering di applicazioni Java SE con Terracotta Guido Anselmi [email_address] Java User Group Milano http://www.jugmilano.it
  2. 2. Sommario <ul><li>Cos'è Terracotta ed a cosa serve
  3. 3. Ambiti di utilizzo
  4. 4. Le basi del clustering in Terracotta
  5. 5. Object Roots e Clustered Objects
  6. 6. Virtual Heap
  7. 7. Thread coordination e Locks
  8. 8. Esempi di sincronizzazione/coordinamento tra JVM diverse </li></ul>
  9. 9. Casi d'uso e definizioni Terracotta is a transparent clustering service for Java applications I tipici casi d'uso di Terractotta possono rientrare nelle seguenti macro categorie: • Distributed cache • Database offload • Session replication • Workload partitioning
  10. 10. Overview Terracotta è un servizio di clustering trasparente . “ Trasparente ” è riferito al linguaggio Java, in cui il clustering è ottenuto senza alcun modello di programmazione o API specifiche. “ Clustering ” indica la capacità di consentire a macchine e processi Java multipli di lavorare insieme sugli stessi dati e di poter comunicare tra di loro utilizzando semplicamente oggetti in memoria e threading logic. Terracotta consente alle applicazioni Java di girare su quante macchine necessario, senza alcuna modifica specifica. Non viene alcun modello specifico di programmazione come clustered caching, EJB, o anche Hibernate o Spring. Terracotta può prendere un'applicazione esistente e scalarla trasparentemente su molte macchine.
  11. 11. POJO Clustering-Instrumented classes Affinchè Terracotta possa effettivamente operare sul nostro codice ( bytecode in realtà), occorre indicare nella configurazione quali classi devono essere “ispezionate e controllate”. Questo avviene tramite il file di configurazione, nella seguente sezione: < instrumented-classes > < include > < class-expression > it.jugmilano.terracotta.example1 ..* </ class-expression > </ include > </ instrumented-classes > Quali classi devono essere instrumented? Per ragioni di performance è bene limitare l'insieme a quello delle classi che usano root objects.
  12. 12. POJO Clustering - Roots Un oggetto definito come root è l'elemento radice di un grafo di oggetti clusterizzati. Qualunque variabile di una classe può esere dichiarata come root. La prima volta che nel codice java viene assegnato un valore ad un oggetto root, Terracotta trasforma lo stesso in clustered object, allocandolo sullo heap condiviso. In questo processo, Terracotta naviga l'intero grafo degli oggetti raggiungibili dalla root, ed essi vengono a loro volta allocati sullo heap condiviso. Le roots sono dichiarate nel file di configurazione di Terracotta <roots> ... <root> <field-name> my.package.MyClass.myRootField </field-name> </root> </roots>
  13. 13. POJO Clustering - Roots I fields dichiarati come root assumono una speciale semantica 1) La prima volta che un field root viene assegnato da una JVM, la root è creata nel cluster Terracotta. 2) Una volta assegnato, il valore di un field root non può essere cambiato. Tutti i successivi assegnamenti, di qualunque JVM, vengono ignorati . 3) L'oggetto top level di un grafo root, non viene mai reclamato dal garbage collector distribuito di Terracotta. Il server Terracotta ha un garbage collector distribuito che rimuove i clustered objects non più referenziati, ossia non più raggiungibili da nessuna root (non facenti parte del grafo di nessuna root) Le roots hanno lo stesso ciclo di vita del clustered heap, e non sono legate alla singola JVM.
  14. 14. POJO Clustering - Roots Ma come fa terracotta a trasformare in maniera trasparente una variabile d'istanza o statica in un oggetto condiviso? Terracotta opera esclusivamente a livello di bytecode. Guidato da quanto indicato nella sezione instrumented-classes, opera una ricerca sulla presenza di oggetti root, e ne trasforma il bytecode. Terracotta si inserisce tra la logica applicativa e la memoria della JVM, ispezionando tutte le chiamate allo heap che coinvolgono roots objects. In particolare, tutte le letture/scritture sullo heap che coinvolgono root objects vengono sostituite da letture/scritture sul clustered heap. HEAPREAD() -> CLUSTEREDHEAPREAD() HEAPWRITE() -> CLUSTEREDHEAPWRITE()
  15. 15. POJO Clustering - Locks Quando diversi threads accedono concorrentemente gli stessi dati sullo heap, speciali precauzioni devono essere prese per evitare interferenze distruttive tra di essi. Naturalmente la cosa è ancora valida quando diversi threads su diverse jvm accedono contemporaneamente lo stesso oggetto sul clustered heaps. Su singola JVM, java sin dagli albori offre meccanismi integrati di mutua esclusione e collaborazione, nella forma del costrutto synchronized e dei metodi di Object wait e notify. Nelle ultime versioni del linguaggio è stato inoltre integrato il package java.util.concurrent , rendendo java un linguaggio con un supporto di primissimo livello al multithreading.
  16. 16. POJO Clustering - Locks Cosa deve cambiare nel codice quando mutua escliusione e collaborazione assumono una valenza a livello di cluster? Assolutamente nulla! Terracotta fornisce esattamente le stesse garanzie di serializzazione degli accessi, coordinamento e visibilità a thread in differenti JVM rispetto a quanto fa la singola JVM sui suoi threads/heap. I meccanismi che Terracotta utilizza per ottemperare a queste semantiche sono i locks. Terracotta amplia la semantica dei lock built in di Java in modo da dargli un effetto a livello di cluster. Il lock clusterizzato è iniettato nel bytecode in base a quanto specificato nella sezione lock
  17. 17. POJO Clustering - Locks <locks> <autolock> <lock-level>write</lock-level> <method-expression>void HelloWorld.method(..)</method-expression> </autolock> </locks> Questa configurazione istruisce terracotta di ispezionare tutti i metodi che matchano la method-expression dentro le instrumented-classes, verificare se al loro interno ci sono accessi synchronized a fields root e, nel caso, sostituire il lock jvm con uno clustered. In luogo di <autolock> è possibile specificare dei <named-locks> La differenza tra i due è che il secondo agisce sempre a livello di intero metodo, mentre il primo onora i blocchi synchronized presenti dentro i metodi.
  18. 18. POJO Clustering - Locks A differenza di Java, i lock di Terracotta hanno diversi livelli: • write • synchronous-write • read locks Write locks: sono i classici lock di mutua esclusione: essi garantiscono che solo un thread nell'intero cluster possa ottenere l'accesso all'oggetto protetto. Synchronous write locks aggiungono la garanzia che il lock non sia rilasciato fin quando le modifiche effettuate dal thread corrente non siano effettivamente propagate al cluster. Read locks: consentono a diversi thread di acquisire il lock sull'oggetto, a patto di non effettuare nessun operazione di scrittura (pena eccezione runtime) Nessun thread può acquisire un lock a livello write se altri thread detengono un lock a livello read. Inoltre a nessun thread è consentito di ottenere un lock read se un altro thread detiene un lock a livello write.
  19. 19. Esempio1 Immaginiamo di avere un insieme di threads il cui compito consiste unicamente nell'estrarre dei Job da un coda condivisa, elaborarli e cambiarne lo stato una volta terminato. Tali threads non devono necessariamente essere eseguiti sulla stessa JVM Job1 Job1 Job1 Job1 Job1 Job1 Jobn Job4 Job3 Job2 JVM1 thread1-3 thread1-2 thread1-1 JVM2 thread2-3 thread2-2 thread2-1 JVM3 thread3-3 thread3-2 thread3-1
  20. 20. Esempio1 La coda è evidentemente un oggetto condiviso, quindi va protetta dall'accesso concorrente da parte di thread differenti (che siano sulla stessa o su diverse JVM) Una prima, molto semplificata, soluzione è la seguente: public class SimpleJobQueue implements JobQueue { private List<Job> jobs = new ArrayList<Job>(); public SimpleJobQueue(int size){ for (int i=0;i<size;i++){ jobs.add(new SimpleJob()); } } public Job getJob(Job job) { return null; } public Job getJobAt(int index) { return jobs.get(index); } }
  21. 21. Esempio1 Dove Job è un'interfaccia che potremmo implementare nel modo seguente public interface Job { public static final int NOT_ASSIGNED = 0; public static final int ASSIGNED = 1; public static final int COMPLETED = 2; public void changeStatus(int status); public int getStatus(); } public class SimpleJob implements Job { private int jobStatus; public SimpleJob(){ jobStatus = NOT_ASSIGNED ; } public void changeStatus(int status) { this.jobStatus = status; } public int getStatus() { return jobStatus; } }
  22. 22. Esempio1 Ed infine il terzo attore, il thread che fa il lavoro sporco, prelevandolo dalla coda. public class SimpleWorker implements Runnable { .................................... public void run() { int status; Job job; synchronized ( queue ) { job = queue.getJobAt( index ); status = job.getStatus(); log(&quot;Extracted Job &quot; + index + &quot; in status &quot; + status); if (status == Job. NOT_ASSIGNED ) { job.changeStatus(Job. ASSIGNED ); log(&quot;Assigned Job &quot; + index ); try {Thread. sleep (1000);} catch(InterruptedException e){ } } job.changeStatus(Job. COMPLETED ); log(&quot;Completed Job &quot; + index ); } else { log(&quot;Job &quot; + index + &quot; Allready Assigned - Nothing TO DO&quot;); } } }
  23. 23. Esempio1 Vogliamo adesso testare il nostro piccolo sistema, costruendo una coda contenente 10 jobs e lanciando 30 diversi threads che accedono la coda stessa, in tre diverse JVM. Senza troppa sorpresa, occorre scrivere una classe con un metodo main e lanciarlo tre volte, ad esempio passandolo all'interprete java in tre diverse shell. Proviamo a scriverlo.
  24. 24. Esempio1 public class SimpleMain { JobQueue queue = new SimpleJobQueue ( 10 ); CyclicBarrier barrier = new CyclicBarrier ( 3 ); public void launch ( int base ) { launchThreads( queue, base); try { barrier.await(); } catch (Exception e) { e.printStackTrace(); } System. out .println(&quot;-----------------------------------&quot;); System. out .println(&quot;All threads completed their job. n&quot; + queue); } private void launchThreads(JobQueue queue, int blockNumber){ for (int i=0; i < 10; i++) { new Thread( new SimpleWorker(&quot;worker&quot; + (i + blockNumber) , queue, i,) ).start(); } } public static void main(String[] s) { int base = 0; if ( s.length==1 ) { base = Integer. parseInt (s[0]); } new SimpleMain().launch ( base ); try { barrier.await(); } catch ( Exception e ) { e.printStackTrace(); } } }
  25. 25. Esempio1 Ed infine questa è la configurazione di Terracotta per ottenere quanto descritto <? xml version = &quot;1.0&quot; encoding = &quot;UTF-8&quot; ?> < con:tc-config xmlns:con = &quot;http://www.terracotta.org/config&quot; > < system > < configuration-model > development </ configuration-model > </ system > < servers > < server name = &quot;localhost&quot; > < dso-port > 9510 </ dso-port > < jmx-port > 9520 </ jmx-port > < data > terracotta/server-data </ data > < logs > terracotta/server-logs </ logs > </ server > </ servers > < clients > < logs > terracotta/client-logs </ logs > </ clients > </ con:tc-config >
  26. 26. Esempio1 < application > < dso > < instrumented-classes > < include > < class-expression > *..* </ class-expression > </ include > </ instrumented-classes > < locks > < autolock > < method-expression > * *..*(..) </ method-expression > < lock-level > write </ lock-level > </ autolock > </ locks > < roots > < root > < field-name > it.jugmilano.terracotta.example1.main.SimpleMain.queue </ field-name > </ root > < root > < field-name > it.jugmilano.terracotta.example1.main.SimpleMain.barrier </ field-name > </ root > </ roots > </ dso > </ application >
  27. 27. Esempio1 A questo punto lanciamo il server Trerracotta ed infine, mandiamo in esecuzione il nostro esempio set /p base=Please enter thread name base: cd C:programmijavaworkspacesJugTerracottatargetclasses dso-java -Dtc.config=../tc-config-simple-worker.xml it.jugmilano.terracotta.example1.main.SimpleMain %base% Lanciamo questo semplice script in tre diverse shell ed il gioco è fatto Quando il server Terracotta è in esecuzione, lanciare un main Java con Terracotta abilitato comporta semplicemente lanciare l'interprete java con pochi JVM arguments. Se vogliamo risparmiarci questa incombenza, possiamo utilizzare lo script dso-java che lo fa automaticamente
  28. 28. Esempio1 Prendiamo in esame le prime linee di codice significative JobQueue queue = new SimpleJobQueue ( 10 ); CyclicBarrier barrier = new CyclicBarrier ( 33 ); In esse vengono sullo heap due diversi oggetti; ma su quale heap? E' chiaro che senza Terracotta, le tre vm in esecuzione lavorerebbero su tre spazi di memoria completamente separati, e quindi non ci sarebbe modo di far condividere la coda e la barriera a tutti i threads in esecuzione. E' evidente che questi due oggetti devono essere delle root, ossia oggetti che Terracotta costruisce sullo heap condiviso e sui quali ha pieno controllo. In tal modo, alla prima assegnazione, Terracotta alloca sul clustered heap entrambi gli oggetti.
  29. 29. Esempio1 Primo main esegue: JobQueue queue = new SimpleJobQueue ( 10 ); La variabile queue è dichiarata come root, Terracotta verifica che sullo heap condiviso essa non è ancora mai stata assegnata e procede alla sua istanziazione. Quando il secondo ed il terzo main eseguono la stessa operazione, Terracotta accede al clustered heap, verifica che la root queue è già stata assegnata, ed ignora l'istruzione. Tutte le successive operazioni sulla variabile queue (e sul grafo di oggetti ad essa collegati) avvengono sul clustered heap e NON sul local heap.
  30. 30. Esempio1 JVM X augmented bytecode bytecode
  31. 31. Esempio2 Il nostro primo esempio ha diversi difetti In particolare la gestione della sincronizzazione è un evidente collo di bottiglia synchronized ( queue ) { job = queue.getJobAt( index ); status = job.getStatus(); log(&quot;Extracted Job &quot; + index + &quot; in status &quot; + status); } Questo codice guadagna un lock esclusivo sull'oggetto queue, impedendo ad ogni altro thread di accedervi (altri eventuali thread si bloccano nell'entry set). Essendo tuttavia queue definito come root ed essendo la classe SimpleWorker una instrumented class, tutti i thread di tutte le Jvm in esecuzione nel cluster devono onorare tale lock !!
  32. 32. Esempio2 Proviamo a fare di meglio, diminuendo le contese. In particolare, poiché nel nostro esempio semplificato ciascun thread sa a priori a quale Job della coda deve accedere, potremmo dividere la politica di locking a livello del singolo job. public class ConcurrentJobQueue implements JobQueue{ private List<Job> jobs = new ArrayList<Job>(); private List<Lock> locks = new ArrayList<Lock>() ; public ConcurrentJobQueue( int size){ for ( int i=0;i<size;i++){ jobs.add( new SimpleJob()); locks.add( new ReentrantLock()); } } public Job getJobAt( int index) { return jobs.get(index); } public Lock getLockAt( int index) { return locks.get(index); }
  33. 33. Esempio2 Adesso i nostri worker cambiano la propria politica di accesso alla coda public void run() { int status; Job job; queue.getLockAt(index).lock(); job = queue.getJobAt(index); status = job.getStatus(); log(&quot;Extracted Job &quot; + index + &quot; in status &quot; + status); if (status == Job. NOT_ASSIGNED ) { job.changeStatus(Job. ASSIGNED ); log(&quot;Assigned Job &quot; + index); queue.getLockAt(index).unlock(); t ry { Thread. sleep (1000); } catch (InterruptedException e) { e.printStackTrace(); } queue.getLockAt(index).lock(); job.changeStatus(Job. COMPLETED ); log(&quot;Completed Job &quot; + index); queue.getLockAt(index).unlock(); } else { log (“Nothing TO DO”); queue.getLockAt(index).unlock(); } }
  34. 34. Esempio2 Il file di configurazione di Terracotta non deve essere rivoluzionato, anzi viene addirittura semplificato. < application > < dso > < instrumented-classes > < include > < class-expression > *..* </ class-expression > </ include > </ instrumented-classes > < roots > < root > < field-name > it.jugmilano.terracotta.example2.main.ConcurrentMain.queue </ field-name > </ root > < root > < field-name > it.jugmilano.terracotta.example2.main.ConcurrentMain.barrier </ field-name > </ root > </ roots > </ dso > </ application >
  35. 35. Esempio3 Complichiamo ancora lo scenario; finora i nostri threads lavorano in esclusione; il primo che guadagna l'accesso al job (entry della coda condivisa) effettua tutto il lavoro, gli altri aspettano passivamente. In uno scenario più realistico, diversi threads potrebbero lavorare in collaborazione tra loro. Ad esempio il primo che guadagna l'accesso effettua un primo cambio di stato, il secondo un altro e così via fino ad arrivare nello stato finale ove il job è effettivamente stato completato. Per rendere le cose più interessanti, scriviamo un worker generico in grado di riconoscere lo stato del job corrente e di comportarsi di conseguenza. Questo comporta la necessità di ripensare leggermente i diversi attori.
  36. 36. Condition Le Condition, a differenza dei classici metodi di Object, consentono al singolo oggetto di comportarsi come se avesse wait-set multipli, Lock -> rimpiazza synchronized Condition -> rimpiazza i metodi dei monitor di Object Le Conditions danno ai threads un mezzo a per sospendere la propria esecuzione (&quot; wait &quot;) fin quando notificati (“ signal ”) da un altro thread. La Condition stessa è una shared resource, e per tale motivo dev'essere protetta da un lock. Mettersi in wait su una Condition rilascia atomicamente il lock detenuto su di essa. Lock lock = new ReentrantLock(); Condition cA = lock.newCondition(); Condition cB = lock.newCondition();
  37. 37. Condition I metodi offerti da Condition sono analoghi a quelli di Object: void await() sospende il thread corrente finquando signalled o interrupted . Il lock associato con la Condition è atomicamente rilasciato ed il thread corrente diventa non più utilizabile dallo scheduler della JVM Il thread ritorna schedulabile solo quando un altro thread invoca signal() o signalAll() sulla stessa Condition, Se il thread ritorna schedulabile, esso è in contesa per guadagnare il Lock. Prima che await() possa ritornare, il thread corrente deve riguadagnare il lock associato con la Condition. Quando il thread riprende l'esecuzione, è garantito che detenga il lock .
  38. 38. Esempio3 Per prima cosa il Job cambia definizione: public interface CollaborativeJob { public static final int INITIAL_STEP = 0; public static final int STEP_1 = 1; public static final int STEP_2 = 2; public static final int FINAL_STEP = 3; public void changeStatus( int status); public int getStatus(); } public class SimpleCollaborativeJob implements CollaborativeJob { private int jobStatus; public SimpleCollaborativeJob(){ jobStatus = INITIAL_STEP ; } public void changeStatus( int status) { this .jobStatus = status; } public int getStatus() { return jobStatus; } }
  39. 39. Esempio3 Anche la coda necessita di essere modificata, aggiungendo le strutture necessarie ad implementare i meccanismi di collaborazione public class CollaborativeJobQueue implements JobQueue{ private List<CollaborativeJob> jobs = new ArrayList<CollaborativeJob>(); private List<Lock> locks = new ArrayList<Lock>(); private List<Condition> waitSets = new ArrayList<Condition>(); public CollaborativeJobQueue( int size){ for ( int i=0;i<size;i++){ jobs.add( new SimpleCollaborativeJob()); Lock lock = new ReentrantLock(); locks.add(lock); waitSets.add(lock.newCondition()); } } public CollaborativeJob getJobAt( int index) { return jobs.get(index); } public Lock getLockAt( int index) { return locks.get(index); } public Condition getWaitSetAt( int index) { return waitSets.get(index); }
  40. 40. Esempio3 Ed infine il nuovo worker public void run() { CollaborativeJob job; queue.getLockAt(index).lock(); job = queue.getJobAt ( index ); try { if ( job.getStatus() != CollaborativeJob. FINAL_STEP ) { while (desiredStatus - job.getStatus() > 1) { log(&quot;Extracted Job &quot; + index + &quot; in status &quot; + job.getStatus() + &quot; waiting desiredstatus= &quot; + desiredStatus); queue.getWaitSetAt(index).await(); } Thread. sleep (1000); job.changeStatus(desiredStatus); log(&quot;Worked on Job &quot; + index + &quot; new status= &quot; + job.getStatus() + &quot; desiredstatus= &quot; + desiredStatus); log(&quot;Job &quot; + index + &quot; completed &quot;); queue.getWaitSetAt(index).signalAll(); queue.getLockAt(index).unlock(); } else { log(&quot;Nothing TO DO status= &quot; + job.getStatus() + &quot; desiredstatus= &quot; + desiredStatus); queue.getLockAt(index).unlock(); } } catch (InterruptedException e) { queue.getLockAt(index).unlock(); e.printStackTrace(); } }
  41. 41. Esempio3 Come cambia la configurazione di Terracotta? In nessun modo! Terracotta onora la semantica di java.util.concurrent, non occorre nessuna configurazione particolare. L'unico compito richiesto allo sviluppatore è la correttezza del comportamento run time e l'assenza di race-conditions ed errori time-depending , esattamente come se si programmasse in un ambiente concorrente puro. Quest'ultimo esempio illustra perfettamente la totale trasparenza di Terracotta nel fornire allo sviluppatore un ambiente clusterizzato ed un reale parallelismo tra i threads java. Si pensi per contro a quanto sarebbe stato più complicato ed invasivo realizzare questa stessa soluzione utilizzando altre soluzioni del mondo Java (database, JMS, RMI...)
  42. 42. Struttura esempi
  43. 43. Conclusioni Terracotta è uno strumento estremamente complesso e potente, ma allo stesso tempo semplice da utilizzare, avendo esperienza di programmazione concorrente. I concetti illustrati sono alla base di soluzioni di grid computing , realizzabili con basso costo e difficoltà ridotta implementativa. Ad esempio, tramite terracotta ed i concetti di root, lock ed instrumented-classes è abbastanza semplice realizzare un effettivo pattern master-worker , utilizzabile per sistemi di produzione ad alta affidabilità ed in grado di rispondere ad elevate esigenze prestazionali.
  44. 44. Titolo ---
  45. 45. Titolo ---
  46. 46. Titolo ---
  47. 47. Titolo ---
  48. 48. Titolo ---

×