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
}