1/50 Ada Vlákna v jazyce Java Monitory a synchronizace Vláknové programování část II Lukáš Hejmánek, Petr Holub {xhejtman,hopet}@ics.muni.cz Laboratoř pokročilých síťových technologií PV192 2013–02–26 2/50 Ada Vlákna v jazyce Java Monitory a synchronizace Přehled přednášky Ada Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace 3/50 Ada Vlákna v jazyce Java Monitory a synchronizace Ada # " ! “Regression testing?” What’s that? If it compiles, it is good, if it boots up it is perfect. – Linus Torvalds ' & $ % Compilable but broken code is even worse than working code. – Alan Cox during a bright moment on the linux-kernel list     Ada: Ideally, when compiles fine it also runs fine. 4/50 Ada Vlákna v jazyce Java Monitory a synchronizace Ada Ada 83/95/2005 jazyk orientovaný na spolehlivé aplikace: vojáci, letectví, ... WORM: write once read many silně typovaný jazyk podpora paralelismu enkapsulace, výjimky, objekty, správa paměti, atd. GNAT ◾ volně dostupný překladač, frontend k GCC materiály na webu ◾ (Annotated) Reference Manual http://www.adaic.org/standards/ada05.html ◾ http://stwww.weizmann.ac.il/g-cs/benari/books/index.html#ase ◾ http://en.wikibooks.org/wiki/Programming:Ada ◾ http://www.adahome.com/Tutorials/Lovelace/lovelace.htm ◾ http://www.pegasoft.ca/resources/boblap/book.html 5/50 Ada Vlákna v jazyce Java Monitory a synchronizace Na co se podívat Struktura balíků, enkapsulace, pojmenování souborů Typový systém Ada, typy a podtypy, ukazatele (access vs. access all), generika, objekty, atributy proměnných Správa paměti Generické kontejnery Volby kompilace: gnatmake hello.adb vs. gnatmake -gnatya -gnatyb -gnatyc -gnatye -gnatyf -gnatyi -gnatyk -gnatyl -gnatyn -gnatyp -gnatyr -gnatyt -g -gnato -gnatf -fstack-check hello.adb 6/50 Ada Vlákna v jazyce Java Monitory a synchronizace Co v Adě neuděláte ... tedy co v ní neuděláte (takhle). 1 if(c = ntoa(b)) {} 7/50 Ada Vlákna v jazyce Java Monitory a synchronizace Co v Adě neuděláte ... tedy co v ní neuděláte (takhle). 1 send(to, from, count) register short *to, *from; 3 register count; { 5 register n = (count + 7) / 8; switch(count % 8) { 7 case 0: do { *to = *from++; case 7: *to = *from++; 9 case 6: *to = *from++; case 5: *to = *from++; 11 case 4: *to = *from++; case 3: *to = *from++; 13 case 2: *to = *from++; case 1: *to = *from++; 15 } while(--n > 0); } 17 } Zdroj: https://en.wikipedia.org/wiki/Duff%27s_device 8/50 Ada Vlákna v jazyce Java Monitory a synchronizace Co v Adě neuděláte ... tedy co v ní neuděláte (takhle). 1 if(c = ntoa(b)) {} 3 #define _ -F<00||--F-OO--; int F=00,OO=00;main(){F_OO();printf("%1.3f\n",4.*-F/OO/OO);}F_OO() 5 { _-_-_-_ 7 _-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_ 9 _-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_ 11 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ 13 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ 15 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_ 17 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_ 19 _-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_ 21 _-_-_-_ } Zdroj: http://www0.us.ioccc.org/1988/westley.c 9/50 Ada Vlákna v jazyce Java Monitory a synchronizace Ada: kontejnery with Ada.Containers.Ordered_Sets; 2 with Ada.Containers.Hashed_Sets; with Ada.Containers.Hashed_Maps; 4 package Priklad_Kolekci is 6 function Unbounded_String_Hash (S : Unbounded_String) 8 return Hash_Type; 10 package UString_Int_Hash is new Ada.Containers.Hashed_Maps ( Key_Type => Unbounded_String, 12 Element_Type => Integer, Hash => Unbounded_String_Hash, 14 Equivalent_Keys => "="); 16 package UStringSet is new Ada.Containers.Hashed_Sets ( Element_Type => Unbounded_String, 18 Hash => Unbounded_String_Hash, Equivalent_Elements => "="); 10/50 Ada Vlákna v jazyce Java Monitory a synchronizace Ada: kontejnery 1 procedure Output_Host_Set (HostSet : UStringSet.Set) is use UStringSet; 3 Cur : UStringSet.Cursor; Is_Tag_Open : Boolean := False; 5 begin Cur := First (HostSet); 7 if Cur /= UStringSet.No_Element then Open_Tag (Is_Tag_Open, " "); 9 while Cur /= UStringSet.No_Element loop Put_Line (" " & To 11 _String (Element (Cur)) & ""); Cur := Next (Cur); 13 end loop; Close_Tag (Is_Tag_Open, " " 15 ); end if; 17 exception 19 when An_Exception : others => Syslog (LOG_ERR, "State dump failed! " & 21 & Exception_Information (An_Exception)); Close_Tag (Is_Tag_Open, " " 23 ); end Output_Host_Set; 25 end Priklad_Kolekci 11/50 Ada Vlákna v jazyce Java Monitory a synchronizace Instalace GNATu Instalační soubory jsou ve studijních materiálech ◾ /el/1433/jaro2011/PV192/um/23046574/ ◾ Linux x86 32 b ◾ Linux x86 64 b ◾ Windows Součásti: GNAT GPL Ada Ada compiler, debugger, tools, libraries AUnit gpl-2010 Ada unit testing framework SPARK GPL SPARK Examiner and Simplifier (static prover) GNATbench Ada plugins for the Eclipse/Workbench IDEs PolyORB gpl-2010 CORBA and Ada distributed annex AWS gpl-2.8.0 Ada web server library ASIS gpl-2010 Library to create tools for Ada software AJIS gpl-2010 Ada Java interfacing suite GNATcoll gpl-2010 Reusable Ada components library GtkAda gpl-2.14.1 Create modern native GUIs in Ada XMLAda gpl-3.2.1 Library to process XML streams Florist gpl-2010 Interface to POSIX libraries (pouze pro Linux) Win32 Ada gpl-2010 Ada API to the Windows library (pouze pro Windows) 12/50 Ada Vlákna v jazyce Java Monitory a synchronizace Instalace GNATu Instalace překladače Linux: ◾ adacore-X86LNX-201102271805.zip: x86-linux/gnatgpl-gpl-2010/gnat-gpl-2010-i686-gnu-linux-libc2. 3-bin.tar.gz gnat-2010-i686-gnu-linux-libc2.3-bin ./doinstall Windows: ◾ adacore-X86WIN-201102271212.zip: x86-windows/gnatgpl-gpl-2010/gnat-gpl-2010-1-i686-pc-mingw32-bin. exe 13/50 Ada Vlákna v jazyce Java Monitory a synchronizace Úkol – Ada Naprogramujte ekvivalent fgrep-u ◾ podpora voleb -i, -r, -n 14/50 Ada Vlákna v jazyce Java Monitory a synchronizace Přehled přednášky Ada Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace 15/50 Ada Vlákna v jazyce Java Monitory a synchronizace Vlákna v jazyce Java Mechanismy ◾ potomek třídy Thread ◾ Executory ◾ objekt implementující úlohu pro Executor objekt implementující interface Runnable (metoda run()) objekt implementující interface Callable (metoda call()) Synchronizace a viditelnost operací Implementace monitorů pomocí synchronized Signalizace mezi objekty: wait, notify, notifyAll Knihovny java.util.concurrent 16/50 Ada Vlákna v jazyce Java Monitory a synchronizace Třída Thread Základní třída pro vlákna Metoda run() ◾ „vnitřnosti“ vlákna ◾ přepisuje se vlastním kódem Metoda start() ◾ startování vlákna ◾ za normálních okolností nepřepisuje! ◾ pokud už se přepisuje, je třeba volat super.start() 17/50 Ada Vlákna v jazyce Java Monitory a synchronizace Třída Thread 1 public class PrikladVlakna { 3 static class MojeVlakno extends Thread { MojeVlakno(String jmenoVlakna) { 5 super(jmenoVlakna); } 7 public void run() { 9 for (int i = 0; i < 10; i++) { System.out.println(this.getName() + 11 ": pocitam vzbuzeni - " + (i + 1)); try { 13 sleep(Math.round(Math.random())); } catch (InterruptedException e) { 15 System.out.println(this.getName() + ": probudil jsem se nenadale! :-|"); 17 } } 19 } } 18/50 Ada Vlákna v jazyce Java Monitory a synchronizace Třída Thread public static void main(String[] args) { 2 new MojeVlakno("vlakno1").start(); new MojeVlakno("vlakno2").start(); 4 } } 19/50 Ada Vlákna v jazyce Java Monitory a synchronizace Viditelnost a synchronizace operací problém viditelnosti změn problém atomicity operací ◾ např. přiřazení do 64-bitového typu (long, double) není nutně atomický! problém synchronizace při změnách hodnot § ¦ ¤ ¥ (nic) > volatile > AtomicXXX > synchronized, explicitní zámky 20/50 Ada Vlákna v jazyce Java Monitory a synchronizace Viditelnost a synchronizace operací public class Nic { 2 private static long cislo = 10000000L; private static boolean pripraven = false; 4 public static class Vlakno extends Thread { 6 public void run() { while (!pripraven) { 8 Thread.yield(); } 10 System.out.println(cislo); } 12 } 14 public static void main(String[] args) { new Vlakno().start(); 16 cislo = 42L; pripraven = true; 18 } } § ¦ ¤ ¥ (nic) > volatile > AtomicXXX > synchronized, explicitní zámky 21/50 Ada Vlákna v jazyce Java Monitory a synchronizace Viditelnost a synchronizace operací Jak to dopadne? ◾ neatomičnost 64-bitového přiřazení ◾ přeuspořádání přiřazení ◾ kterákoli ze změn hodnot nemusí být viditelná ◾ jakkoli... 10.000.000 nebo 42 nebo něco jiného (neatomičnost – vlákno se může trefit mezi přiřazení horní a dolní poloviny 64 b operace) ale také může navždy cyklit (Vlakno neuvidí nastavení pripraven) pročež platí ' & $ % 1. Pokud více vláken čte jednu proměnnou, musí se řešit viditelnost. 2. Pokud více vláken zapisuje do jedné proměnné, musí se synchronizovat. § ¦ ¤ ¥ (nic) > volatile > AtomicXXX > synchronized, explicitní zámky 22/50 Ada Vlákna v jazyce Java Monitory a synchronizace Viditelnost a synchronizace operací volatile ◾ zajišťuje viditelnost změn mezi vlákny ◾ překladač nesmí dělat presumpce/optimalizace, které by mohly ovlivnit viditelnost ◾ u 64 b přiřazení zajišťuje atomičnost ◾ nezajišťuje atomičnost operace načti–změň–zapiš! nelze použít pro thread-safe i++ ◾ lze použít pokud jsou splněny obě následující podmínky 1. nová hodnota proměnné nezávisí na její předchozí hodnotě 2. proměnná se nevyskytuje v invariantech spolu s jinými proměnnými (např. a<=b) např. příznak ukončení nebo jiné události, který nastavuje pouze jedno vlákno – pomohlo by v příkladě třídy Nic (slajd 20) příklady použití: http://www.ibm.com/developerworks/java/library/j-jtp06197.html ◾ pokud si nejsme jisti, použijeme raději silnější synchronizaci § ¦ ¤ ¥ (nic) > volatile > AtomicXXX > synchronized, explicitní zámky 23/50 Ada Vlákna v jazyce Java Monitory a synchronizace Viditelnost a synchronizace operací public class VolatileInvariant { 2 private volatile int horniMez, dolniMez; 4 public int getHorniMez() { return horniMez; } 6 public void setHorniMez(int horniMez) { if (horniMez < this.dolniMez) 8 throw new IllegalArgumentException("Horni < dolni!"); else 10 this.horniMez = horniMez; } 12 public int getDolniMez() { return dolniMez; } 14 public void setDolniMez(int dolniMez) { 16 if (dolniMez > this.horniMez) throw new IllegalArgumentException("Dolni > horni!"); 18 else this.dolniMez = dolniMez; 20 } } § ¦ ¤ ¥ (nic) > volatile > AtomicXXX > synchronized, explicitní zámky 24/50 Ada Vlákna v jazyce Java Monitory a synchronizace Viditelnost a synchronizace operací AtomicXXX ◾ zajišťuje viditelnost ◾ zajišťuje atomičnost operace načti–změň–zapiš nad objektem potřebujeme-li udělat více takových operací synchronně, nelze použít synchronized, explicitní zámky ◾ zajištění viditelnosti ◾ zajištění vyloučení (a tedy i atomičnosti) v kritické sekci § ¦ ¤ ¥ (nic) > volatile > AtomicXXX > synchronized, explicitní zámky 25/50 Ada Vlákna v jazyce Java Monitory a synchronizace Publikování a únik Publikování objektu ◾ zveřejnění odkazu na objekt ◾ thread-safe třídy nesmí publikovat objekty bez zajištěné synchronizace ◾ nepřímé publikování publikování jiného objektu, přes něhož je daný objekt dosažitelný např. publikování kolekce obsahující objekt např. instance vnitřní třídy obsahuje odkaz na vnější třídu ◾ „vetřelecké“ (alien) metody metody, jejichž chování není plně definováno samotnou třídou všechny metody, které nejsou private nebo final – mohou být přepsány v potomkovi předání objektu vetřelecké metodě = publikování objektu 26/50 Ada Vlákna v jazyce Java Monitory a synchronizace Publikování a únik Únik stavu objektu ◾ publikování reference na interní měnitelné (mutable) objekty ◾ v níže uvedeném příkladě může klient měnit pole states ◾ potřeba hlubokého kopírování (deep copy) 1 import java.util.Arrays; 3 public class UnikStavu { private String[] stavy = new String[]{"Stav1", "Stav2", "Stav3"}; 5 public String[] getStavySpatne() { 7 return stavy; } 9 public String[] getStavySpravne() { 11 return Arrays.copyOf(stavy, stavy.length); } 13 } 27/50 Ada Vlákna v jazyce Java Monitory a synchronizace Publikování a únik Únik z konstruktoru ◾ až do návratu z konstruktoru je objekt v „rozpracovaném“ stavu ◾ publikování objektu v tomto stavu je obzvláště nebezpečné ◾ pozor na skryté publikování přes this v rámci instance vnitřní třídy registrace listenerů na události 1 public class UnikZKonstruktoru { public UnikZKonstruktoru(EventSource zdroj) { 3 zdroj.registerListener( new EventListener() { 5 public void onEvent(Event e) { zpracujUdalost(e); 7 } } 9 ); } 11 } 28/50 Ada Vlákna v jazyce Java Monitory a synchronizace Publikování a únik Únik z konstruktoru ◾ když musíš, tak musíš... ale aspoň takto: 1. vytvořit soukromý konstruktor 2. vytvořit veřejnou factory 1 public class BezpecnyListener { private final EventListener listener; 3 private BezpecnyListener() { 5 listener = new EventListener() { public void onEvent(Event e) { 7 zpracujUdalost(e); } 9 }; } 11 public static BezpecnyListener novaInstance(EventSource zdroj) { 13 BezpecnyListener bl = new BezpecnyListener(); zdroj.registerListener(bl.listener); 15 return bl; } 17 } 29/50 Ada Vlákna v jazyce Java Monitory a synchronizace Thead-safe data ad hoc ◾ zodpovědnost čistě ponechaná na implementaci ◾ nepoužívá podporu jazyka ◾ pokud možno nepoužívat 30/50 Ada Vlákna v jazyce Java Monitory a synchronizace Thead-safe data data omezená na zásobník ◾ data na zásobníku patří pouze danému vláknu ◾ týká se lokálních proměnných u primitivních lokálních proměnných nelze získat ukazatel a tudíž je nelze publikovat mimo vlákno ukazatele na objekty je třeba hlídat (programátor), že se objekt nepublikuje a zůstává lokální lze používat ne-thread-safe objekty, ale je rozumné to dokumentovat (pro následné udržovatele kódu) 1 import java.util.Collection; 3 public class PocitejKulicky { public class Kulicka { 5 } 7 public int pocetKulicek(Collection kulicky) { int pocet = 0; 9 for (Kulicka kulicka : kulicky) { pocet++; 11 } return pocet; 13 } } 31/50 Ada Vlákna v jazyce Java Monitory a synchronizace Thead-safe data ThreadLocal ◾ data asociovaná s každým vláknem zvlášť, ukládá se do Thread ◾ používá se často v kombinaci se Singletony a globálními proměnnými ◾ JDBC spojení na databázi nemusí být thread-safe import java.sql.Connection; 2 import java.sql.DriverManager; import java.sql.SQLException; 4 public class PrikladTL { 6 private static ThreadLocal connectionHolder = new ThreadLocal() { 8 protected Connection initialValue() { try { 10 return DriverManager.getConnection("DB_URL"); } catch (SQLException e) { 12 return null; } 14 } }; 16 public static Connection getConnection() { 18 return connectionHolder.get(); } 20 } 32/50 Ada Vlákna v jazyce Java Monitory a synchronizace Thead-safe data Neměnné (immutable) objekty ◾ neměnný objekt je takový jehož stav se nemůže změnit, jakmile je zkonstruován všechny jeho pole jsou final je řádně zkonstruován (nedojde k úniku z konstruktoru) ◾ neměnné objekty jsou automaticky thread-safe ◾ pokud potřebujeme provést složenou akci atomicky, můžeme ji zabalit do vytvoření neměnného objektu na zásobníku a jeho publikaci pomocí volatile odkazu nemůžeme předpokládat atomičnost načti–změň–zapiš (i++ chování) ◾ díky levné alokaci1 nových objektů (JDK verze 5 a výš) se dají efektivně používat 1Do JDK 5.0 se používalo ThreadLocal pro recyklaci bufferů metody Integer.toString. Od verze 5.0 se vždy alokuje nový buffer, je to rychlejší. 33/50 Ada Vlákna v jazyce Java Monitory a synchronizace Thead-safe data Neměnné (immutable) objekty public class NemennaCache { 2 private final String lastURL; private final String lastContent; 4 public NemennaCache(String lastURL, String lastContent) { 6 this.lastURL = lastURL; this.lastContent = lastContent; 8 } 10 public String vemZCache(String url) { if (lastURL == null || !lastURL.equals(url)) 12 return null; else 14 return lastContent; } 16 } 34/50 Ada Vlákna v jazyce Java Monitory a synchronizace Thead-safe data Neměnné (immutable) objekty public class PouzitiCache { 2 private volatile NemennaCache cache = new NemennaCache(null, null); 4 public String nactiURL(String URL) { String obsah = cache.vemZCache(URL); 6 if (obsah == null) { obsah = fetch(URL); 8 cache = new NemennaCache(URL, obsah); return obsah; 10 } else return obsah; 12 } } 35/50 Ada Vlákna v jazyce Java Monitory a synchronizace Bezpečné publikování Je následující třída v pořádku? 1 public class Trida { public class Pytlicek { 3 public int hodnota; 5 public Pytlicek(int hodnota) { this.hodnota = hodnota; 7 } } 9 public Pytlicek pytlicek; 11 public void incializujPytlicek(int i) { 13 pytlicek = new Pytlicek(i); } 15 } 36/50 Ada Vlákna v jazyce Java Monitory a synchronizace Bezpečné publikování Nebezpečné publikování ◾ publikování potenciálně nedokončeného měnitelného objektu ◾ takto by šlo publikovat pouze neměnné objekty (lépe s použitím volatile) 1 public class NebezpecnePublikovani { public class Pytlicek { 3 public int hodnota; 5 public Pytlicek(int hodnota) { this.hodnota = hodnota; 7 } } 9 public Pytlicek pytlicek; 11 public void incializujPytlicek(int i) { 13 pytlicek = new Pytlicek(i); } 15 } 37/50 Ada Vlákna v jazyce Java Monitory a synchronizace Bezpečné publikování Způsoby bezpečného publikování měnitelných objektů 1. inicializace odkazu ze statického inicializátoru 2. uložení odkazu do volatile nebo AtomicReference pole 3. uložení odkazu do final pole (po návratu z konstruktoru! – obzvlášť opatrně) 4. uložení odkazu do pole, které je chráněno zámky/monitorem 5. uložení do thread-safe kolekce (Hashtable, synchronizedMap, ConcurrentMap, Vector, CopyOnWriteArray{List,Set}, synchronized{List,Set}, BlockingQueue, ConcurrentLinkedQueue) ◾ objekt i odkaz musí být publikovány současně 38/50 Ada Vlákna v jazyce Java Monitory a synchronizace Bezpečné publikování Efektivně neměnné objekty ◾ pokud se k objektu chováme jako neměnnému ◾ bezpečné publikování je dostatečné Měnitelné objetky ◾ bezpečné publikování zajistí pouze viditelnost ve výchozím stavu ◾ změny je třeba synchronizovat (zámky/monitory) 39/50 Ada Vlákna v jazyce Java Monitory a synchronizace Bezpečné sdílení objektů Uzavřené ve vlákně Sdílené jen pro čtení ◾ neměnné a efektivně neměnné objekty Thread-safe objekty ◾ zajišťují si synchronizaci uvnitř samy Chráněné objekty ◾ zabalené do thread-safe konstrukcí (thread-safe objektů, chráněny zámkem/monitorem) 40/50 Ada Vlákna v jazyce Java Monitory a synchronizace Ukončování vláken Vlákna by se měla zásadně ukončovat dobrovolně a samostatně ◾ metoda Thread.stop() je deprecated ◾ násilné ukončení vlákna může nechat systém v nekonzistentním stavu výjimka ThreadDeath tiše odemkne všechny monitory, které vlákno drželo objekty, které byly monitory chráněny, mohou být v nekonzistentním stavu ◾ http://java.sun.com/j2se/1.4.2/docs/guide/misc/ threadPrimitiveDeprecation.html Jak na to? ◾ zavést si proměnnou, která bude signalizovat požadavek na ukončení nebo ◾ využít příznak isInterrupted() ◾ použití metody interrupt() ◾ použití I/O blokujících omezenou dobu Vlákna lze násilně ukončovat ve speciálních případech ◾ ExecutorService ◾ Futures 41/50 Ada Vlákna v jazyce Java Monitory a synchronizace Ukončování vláken 1 import static java.lang.Thread.sleep; 3 public class PrikladUkonceni { static class MojeVlakno extends Thread { 5 private volatile boolean ukonciSe = false; 7 public void run() { while (!ukonciSe) { 9 try { System.out.println("...chrnim..."); 11 sleep(1000); } catch (InterruptedException e) { 13 System.out.println("Vzbudil jsem se necekane!"); } 15 } } 17 public void skonci() { 19 ukonciSe = true; } 21 } 42/50 Ada Vlákna v jazyce Java Monitory a synchronizace Ukončování vláken public static void main(String[] args) { 24 try { MojeVlakno vlakno = new MojeVlakno(); 26 vlakno.start(); sleep(2000); 28 vlakno.skonci(); vlakno.interrupt(); 30 vlakno.join(); } catch (InterruptedException e) { 32 e.printStackTrace(); } 34 } } 43/50 Ada Vlákna v jazyce Java Monitory a synchronizace synchronized a monitory Monitory – Hoare, Dijkstra, Hansen, cca 1974 ◾ vynucuje serializovaný přístup k objektu synchronized – základní nástroj pro vyloučení v kritické sekci ◾ v Javě se označuje jako monitor ◾ synchronizuje se na explicitně uvedeném objektu (raději final) nebo (implicitně) na this ◾ Javové monitory nezahrnují podmínky, jsou jednodušší než Hoareho 44/50 Ada Vlákna v jazyce Java Monitory a synchronizace synchronized a monitory 1 import net.jcip.annotations.ThreadSafe; @ThreadSafe 3 public class PrikladSynchronized { Integer cislo; 5 public PrikladSynchronized() { this.cislo = 0; 7 } public PrikladSynchronized(Integer cislo) { 9 this.cislo = cislo; } 11 void pricti(int i) { synchronized (this) { 13 cislo += i; } 15 } synchronized int kolikJeCislo() { 17 return cislo; } 19 } 45/50 Ada Vlákna v jazyce Java Monitory a synchronizace synchronized a monitory Java monitor pattern 1 import net.jcip.annotations.GuardedBy; // http://www.javaconcurrencyinpractice.com/jcip-annotations.jar 3 public class MonitorPattern { 5 private final Object zamek = new Object(); @GuardedBy("zamek") Object mujObject; 7 void metoda() { 9 synchronized (zamek) { // manipulace s objektem mujObject; 11 } } 13 } 46/50 Ada Vlákna v jazyce Java Monitory a synchronizace Sychronized Collections Přímo synchronizované kolekce: Vector, Hashtable Synchronizované obaly: Collection.synchronizedX factory metody Tyto kolekce jsou thread-safe, ale poněkud zákeřné ◾ může být potřeba chránit pomocí zámků složené akce iterace navigace (procházení prvků v nějakém pořadí) podmíněné operace, např. vlož-pokud-chybí (put-if-absent) 47/50 Ada Vlákna v jazyce Java Monitory a synchronizace Sychronized Collections 1 import java.util.Vector; 3 public class PodlaKolekce { public static Object dejPosledni(Vector v) { 5 int posledni = v.size() - 1; return v.get(posledni); 7 } 9 public static void smazPosledni(Vector v) { int posledni = v.size() - 1; 11 v.remove(posledni); } 13 } 48/50 Ada Vlákna v jazyce Java Monitory a synchronizace Sychronized Collections 49/50 Ada Vlákna v jazyce Java Monitory a synchronizace Sychronized Collections Výše uvedené chování nemůže poškodit Vector v ⇒ thread-safe Chování ale bude zmatečné ◾ mezi získání indexu poslední položky a get() ev. remove() se může vloudit jiný remove() ⇒ vyhazování výjimky ArrayOutOfBoundException Lze ošetřit klientským zamykáním, pokud známe objekt, na němž se v sychronizované kolekci dělá monitor 50/50 Ada Vlákna v jazyce Java Monitory a synchronizace Sychronized Collections 1 import java.util.Vector; 3 public class RucneSyncnutaKolekce { public static Object dejPosledni(Vector v) { 5 synchronized (v) { int posledni = v.size() - 1; 7 return v.get(posledni); } 9 } 11 public static void smazPosledni(Vector v) { synchronized (v) { 13 int posledni = v.size() - 1; v.remove(posledni); 15 } } 17 }