1/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend Vláknové programování část III Lukáš Hejmánek, Petr Holub {xhejtman,hopet}@ics.muni.cz Laboratoř pokročilých síťových technologií PV192 2010­03­11 2/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend Přehled přednášky Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend 3/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend Vlákna v jazyce Java Mechanismy potomek třídy Thread Executory objekt implementující vlákno 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 4/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend 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() 5/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend 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 } } 21 public static void main(String[] args) { 23 new MojeVlakno("vlakno1").start(); new MojeVlakno("vlakno2").start(); 25 } } 6/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend 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 7/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend 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 8/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend 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 tre t 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 9/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend 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 jiných proměnných např. příznak ukončení nebo jiné události, který nastavuje pouze jedno vlákno ­ pomohlo by v příkladě třídy Nic (slajd 7) 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 10/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend Viditelnost a synchronizace operací 1 public class VolatileInvariant { private volatile int horniMez, dolniMez; 3 public int getHorniMez() { return horniMez; } 5 public void setHorniMez(int horniMez) { 7 if (horniMez < this.dolniMez) throw new IllegalArgumentException("Horni < dolni!"); 9 else this.horniMez = horniMez; 11 } 13 public int getDolniMez() { return dolniMez; } 15 public void setDolniMez(int dolniMez) { if (dolniMez > this.horniMez) 17 throw new IllegalArgumentException("Dolni > horni!"); else 19 this.dolniMez = dolniMez; } 21 } § ¤ (nic) > volatile > AtomicXXX > synchronized, explicitní zámky 11/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend 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 12/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend 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ě de nová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 13/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend 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 } 14/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend 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 } 15/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend 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 } 16/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend Thead-safe data ad hoc zodpovědnost čistě ponechaná na implmentaci nepoužívá podporu jazyka pokud možno nepoužívat 17/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend 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 } } 18/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend 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 } 19/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend 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é alokaci nových objektů (JDK verze 5 a výš) se dají efektivně používat Do JDK 5.0 se používalo ThreadLocal pro recyklaci bu erů metody Integer.toString. Od verze 5.0 se vždy alokuje nový bu er, je to rychlejší. 20/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend 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 } 21/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend 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 } } 22/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend 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 } 23/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend 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 od final pole ­ bezpečné až po návratu z konstruktoru 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ě 24/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend 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) 25/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend 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) 26/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend 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 27/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend 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 } 28/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend 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 } } 29/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend synchronized a monitory Monitory ­ Hoare, Dijkstra, Hansen, cca 1974 vynucuje serializovaný přístup k objektu implementace Hoarových monitorů pro Javu: http://www.engr.mun.ca/%7Etheo/Misc/monitors/monitors.html http: //www.javaworld.com/javaworld/jw-10-2007/jw-10-monitors.html 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 30/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend 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 } 31/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend 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 } 32/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend 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) 33/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend 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 } 34/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend Sychronized Collections 35/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend 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 36/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend 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 } 37/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend Signalizace mezi objekty De nováno pro každý Object Musí být vlastníkem monitoru pro daný Objekt synchronized sekce Metoda wait() usnutí do doby noti kace při usnutí se vlákno vzdá monitoru po probuzení čeká, než monitor může opět získat Metoda notify() noti kace jednoho z čekajících pokud je čekajících více, vybere se jeden (libovolně dle implementace) vybuzené vlákno pokračuje až poté, co se noti kující vlákno vzdá monitoru Metoda notifyAll() noti kace všech vláken čekajících na daném objektu 38/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend Signalizace mezi objekty 39/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend Suspendování vláken Metody Thread.suspend() a Thread.resume jsou inherentně nebezpečné ­ deadlocky Emulace pomocí wait() a notify() 40/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend Suspendování vláken import static java.lang.Thread.sleep; 2 public class PrikladSuspendu { 4 static class MojeVlakno extends Thread { private volatile boolean ukonciSe = false; 6 private volatile boolean spi = false; 8 public void run() { while (!ukonciSe) { 10 System.out.println("...makam..."); try { 12 sleep(500); synchronized (this) { 14 while (spi) { wait(); 16 } } 18 } catch (InterruptedException e) { System.out.println("Necekane probuzeni!"); 20 } } 22 System.out.println("...domakal jsem..."); } 24 public void skonci() { 26 ukonciSe = true; } 41/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend Suspendování vláken public void usni() { 30 spi = true; } 32 public void vzbudSe() { 34 spi = false; synchronized (this) { 36 this.notify(); } 38 } } 40 public static void main(String[] args) { 42 try { MojeVlakno vlakno = new MojeVlakno(); 44 vlakno.start(); sleep(2000); 46 vlakno.usni(); sleep(2000); 48 vlakno.vzbudSe(); sleep(2000); 50 vlakno.skonci(); vlakno.join(); 52 } catch (InterruptedException e) { e.printStackTrace(); 54 } } 56 } 42/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend Vzor producent­konzument Třídy Queue a BlockingQueue metody: offer() přidává na konec fronty (blokuje se v případě BlockingQueue a zaplnění kapacity) nepoužívat add() pro fronty s omezenou kapacitou peek() vrátí prvek ze začátku fronty, ale neodstraní ho z fronty poll() vrátí prvek ze začátku fronty, null pokud je fronta prázdná remove() vrátí prvek ze začátku fronty, výjimka NoSuchElementException pokud je fronta prázdná take() vrátí prvek ze začátku blokující fronty, nebo se zablokuje, dokud je fronta prázdná typy ConcurrentLinkedQueue ­ neblokující, FIFO, efektivní wait-free algoritmus, nesmí obsahovat null PriorityQueue ­ podpora priority (přirozené uspořádání, public interface Comparable) LinkedBlockingQueue ­ blokující obdoba ConcurrentLinkedQueue PriorityBlockingQueue ­ blokující obdoba PriorityQueue SynchronousQueue ­ synchronní blokující fronta (offer() se zablokuje až do odpovídajícího take()) 43/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend Vzor producent­konzument import java.util.*; 2 import java.util.concurrent.*; 4 public class Fronty { public class NeblokujiciFronty { 6 Queue clq = new ConcurrentLinkedQueue(); Queue pq = new PriorityQueue(50); 8 Queue q = new SynchronousQueue(); 10 } 12 public class BlokujiciFronty { BlockingQueue bclq = new LinkedBlockingQueue(30); 14 BlockingQueue bpq = new PriorityBlockingQueue(); 16 void pouziti() { bclq.offer(new Object()); 18 Object o = bclq.peek(); o = bclq.poll(); 20 try { o = bclq.take(); 22 } catch (InterruptedException e) { e.printStackTrace(); 24 } } 26 } 28 } 44/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend Vzor producent­konzument Vzor producent­konzument producenti přidávají práci do fronty (offer()) konzumenti přidávají práci do fronty (take()) zvláště zajímavé se thread pools 45/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend Vzor producent­konzument import java.util.concurrent.*; 2 public class ProducentKonzument extends Thread { 4 public class Task { } 6 BlockingQueue bclq = new LinkedBlockingQueue(); 8 public void run() { Thread producent = new Thread() { 10 public void run() { bclq.offer(new Task()); 12 } }; 14 Thread konzument = new Thread() { 16 public void run() { try { 18 Task t = bclq.take(); } catch (InterruptedException e) { 20 System.out.println("Necekane probuzeni!"); } 22 } }; 24 producent.start(); 26 konzument.start(); } 28 } 46/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend Vzor kradení práce Deque a BlockingDeque umožňují vybírat prvky ze začátku i z konce fronty normální konzumenti vybírají prvky ze začátku fronty vlákna, která se ,,nudí`` mohou převzít práci z konce fronty např. udržování fronty per vlákno, ,,nudící se`` vlákna mohou koukat do cizích front vhodné např. pro situace, kdy si vlákno generuje další práci samo pro sebe (webový crawler) 47/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend Vzor kradení práce import java.util.concurrent.*; 2 public class KradeniPrace { 4 public class Task { } 6 BlockingDeque deque = new LinkedBlockingDeque(20); 8 public void run() { Thread producent = new Thread() { 10 public void run() { deque.offer(new Task()); } }; 12 Thread konzument1 = new Thread() { 14 public void run() { try { 16 Task t = deque.take(); } catch (InterruptedException e) { 18 } } 20 }; 22 Thread konzument2 = new Thread() { public void run() { Task t = deque.pollLast(); } 24 }; 26 producent.start(); konzument1.start(); konzument2.start(); } 28 } 48/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend Další synchronizační prvky semafory počáteční kapacita N ,,permitů`` acquire() získá ,,permit``, eventuálně se zablokuje, pokud permity došly release() vrátí permit 49/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend Další synchronizační prvky závlačka ­ CountDownLatch speciální typ semaforu, z jehož kapacity lze jen odečítat await() čeká, až hodnota klesne na 0 např. čekání na až doběhne n nějakých událostí import java.util.concurrent.CountDownLatch; 2 public class Zavlacka extends Thread { 4 static final int POCET_UDALOSTI = 10; CountDownLatch cdl = new CountDownLatch(POCET_UDALOSTI); 6 public void run() { Thread ridici = new Thread(){ 8 public void run() { for (int i = 0; i < POCET_UDALOSTI; i++) { 10 cdl.countDown(); } 12 } }; 50/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend Další synchronizační prvky závlačka ­ CountDownLatch 14 Thread cekaci = new Thread() { public void run() { 16 try { System.out.println("Musim pockat na " 18 + POCET_UDALOSTI + " udalosti"); cdl.await(); 20 System.out.println("Ted teprv muzu bezet."); } catch (InterruptedException e) { 22 System.out.println("Neocekavane vzbuzeni!"); } 24 } }; 26 cekaci.start(); ridici.start(); } 28 public static void main(String[] args) { 30 new Zavlacka().start(); } 32 } 51/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend Další synchronizační prvky FutureTask podrobně si koncept probereme u Futures a ThreadPoolExecutors je implementována pomocí Callable obdoba Runnable, akorát umožňuje vracet hodnotu metoda get() umožňuje čekat, než je k dispozici návratová hodnota 52/52 Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken Monitory a synchronizace Signalizace a suspend Další synchronizační prvky bariéry umožňuje více vláknům se se jít v jednom místě např. pro iterativní výpočty, kde jedna iterace může být rozdělena na n paralelních a další iterace je závislá na výsledku předchozí iterace zatímco závlačky jsou určeny k čekání na události, bariéry jsou určeny k čekání na jiná vlákna CyclicBarrier ­ bariéra pro opakované setkávání se konstantního počtu vláken pokud se nějaké vlákno vzbudí během await() metody, považuje se bariéra za prolomenou a všichni ostatní čekající dostanou BrokenBarrierException Exchanger výměna dat během bariéry ekvivalent konceptu rendezvous v Adě