1/52 Ada Vlákna v jazyce Java 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 2011–03–03 2/52 Ada Vlákna v jazyce Java Přehled přednášky Ada Základy jazyka GNAT Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken 3/52 Ada Vlákna v jazyce Java 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/52 Ada Vlákna v jazyce Java 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/52 Ada Vlákna v jazyce Java Ada: Hello World! 1 with Ada.Text_IO; 3 procedure Hello is begin 5 Ada.Text_IO.Put_Line ("Hello, world!"); end Hello; normální kompilace gnatmake hello.adb přidané kontroly gnatmake -gnatya -gnatyb -gnatyc -gnatye -gnatyf -gnatyi -gnatyk -gnatyl -gnatyn -gnatyp -gnatyr -gnatyt -g -gnato -gnatf -fstack-check hello.adb 6/52 Ada Vlákna v jazyce Java Ada: balíky Princip zapouzdření ◾ rozdělení funkcionality do balíků (packages) ◾ hierarchie balíků: child packages (Ada95) ◾ privátní část (balíků, chráněných typů) Princip oddělení specifikace a implementace ◾ .ads popisuje rozhraní lze kompilovat i jen proti specifikaci (bez implementace), ale nelze v takovém případě linkovat ◾ .adb je implementace Doporučené pojmenování souborů podle jmen balíků ◾ s/\./-/g Nejsou požadavky na adresářovou strukturu Možnost externalizace implementací balíků 7/52 Ada Vlákna v jazyce Java Ada: procedury, funkce procedury: in, out a in out parametry funkce: pouze in parametry, vrací hodnotu procedure Procedura (A, B : in Integer := 0; 2 C : out Unbounded_String; D : in out Natural) 4 is begin 6 C := To_Unbounded_String(A’Image & " " & B’Image); D := D + 1; 8 end Procedura; 10 function Funkce (A, B: Integer) return String is 12 Retezec : Unbounded_String; Prirozene_Cislo : Natural; 14 begin Procedura (A, B, Retezec, Prirozene_Cislo); 16 Procedura (Retezec, Prirozene_Cislo); Procedura (B => B, A => A, Retezec, Prirozene_Cislo); 18 return To_String (Retezec); end Funkce; 20 type Callback_Procedury is access procedure (Id : Integer; T : String); 22 type Callback_Function is access function (Id : Natural) return Natural; 8/52 Ada Vlákna v jazyce Java Ada: balíky balik.ads: package Balik is 2 type Muj_Typ is private; 4 procedure Nastav_A (This : in out Muj_Typ; 6 An_A : in Integer); 8 function Dej_A (This : Muj_Typ) return Integer; 10 private 12 type Muj_Typ is record 14 A : Integer; end record ; 16 pragma Inline (Dej_A); 18 end Balik; 9/52 Ada Vlákna v jazyce Java Ada: balíky balik.adb: 1 package body Balik is 3 procedure Nastav_A (This : in out Muj_Typ; An_A : in Integer) 5 is begin 7 This.A := An_A; end Nastav_A; 9 function Dej_A (This : Muj_Typ) return Integer is 11 begin return This.A; 13 end Dej_A; 15 end Balik; 10/52 Ada Vlákna v jazyce Java Ada: typy Základní typy ◾ celočíselné, plovoucí, decimální ◾ výčty ◾ pole ◾ záznamy (struktury) ◾ ukazatele (access) ◾ úlohy (tasks) ◾ rozhraní (interfaces) 1 Y : Boolean; S : String; 3 F : Float; Addr : System.Address; 5 type uhel is delta 1 / (60 * 60) range 0.0 .. 360.0; type teplomer is delta 10.0**(-2) digits 10 range -273.15 .. 5000.0; 7 type pole is array (1 .. 10) of Natural; X : String (1 .. 10) := (others => ’ ’); 9 type Enum is (A, B, C); E : Enum := A; 11/52 Ada Vlákna v jazyce Java Ada: typy Neomezené řetězce ◾ omezené velikostí haldy nebo Integer’Last with Ada.Text_IO; use Ada.Text_IO; 2 with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; 4 procedure Strings is S : String := "Muj retezec bla"; 6 begin declare 8 US : Unbounded_String := To_Unbounded_String (S(S’First .. S’Last-4)); 10 begin Put_Line (To_String (US)); 12 Put_Line ("To " & "je " & "vse."); end; 14 end Strings; $ gnatmake strings.adb 2 gcc -c strings.adb gnatbind -x strings.ali 4 gnatlink strings.ali 6 $ ./strings Muj retezec 8 To je vse. 12/52 Ada Vlákna v jazyce Java Ada: typy Anonymní vs. pojmenované typy X : String (1 .. 10) := (others => ’ ’); 2 subtype My_String is String (1 .. 10); Y : My_String := (others => ’ ’); Privátní versus limitované privátní typy type typ_X is private; -- nevidime dovnitr 2 type typ_X is limited private; -- nelze priradit 13/52 Ada Vlákna v jazyce Java Ada: typy Záznamy / Struktury 1 type Car is record Identity : Long_Long_Integer; 3 Number_Wheels : Positive range 1 .. 10; Paint : Color; 5 Horse_Power_kW : Float range 0.0 .. 2_000.0; Consumption : Float range 0.0 .. 100.0; 7 end record; 9 BMW : Car := (Identity => 2007_752_83992434, 11 Number_Wheels => 5, Horse_Power_kW => 190.0, 13 Consumption => 10.1, Paint => Blue); Variantní záznamy, uniony 14/52 Ada Vlákna v jazyce Java Ada: typy Objekty – tagované záznamy 1 type Person is tagged record 3 Name : String (1 .. 10); Gender : Gender_Type; 5 end record; 7 type Programmer is new Person with record 9 Skilled_In : Language_List; end record; 11 function Get_Skills (P : Programmer) return Language_List; 15/52 Ada Vlákna v jazyce Java Ada: typy Typy vs. podtypy type Integer_1 is range 1 .. 10; 2 subtype Integer_2 is Integer_1 range 7 .. 10; A : Integer_1 := 8; 4 B : Integer_2 := A; -- OK 6 type Integer_1 is range 1 .. 10; type Integer_2 is new Integer_1 range 2 .. 8; 8 A : Integer_1 := 8; B : Integer_2 := A; -- nelze! 10 C : Integer_2 := Integer_2 (A); -- OK 16/52 Ada Vlákna v jazyce Java Ada: typy Ukazatele type Day_Of_Month is range 1 .. 31; 2 type Day_Of_Month_Access is access Day_Of_Month; type Day_Of_Month_Access_All is access all Day_Of_Month; 4 for Day_Of_Month_Access’Storage_Pool use Pool_Name; procedure Test (Call_Back: access procedure (Id: Integer; Text: String)); 6 DoM : Day_Of_Month; 8 DoMA : Day_Of_Month_Access := Dom’Access; -- neee DoMAA : Day_Of_Month_Access_All := Dom’Access; -- jo 10 DoMA : Day_Of_Month_Access := new Day_Of_Month; 12 procedure Free is new Ada.Unchecked_Deallocation (Object => Day_Of_Month 14 Name => Day_Of_Month_Access); Free (DoMA); 17/52 Ada Vlákna v jazyce Java Ada: typy Atributy type barvy is (cervena, zelena, modra); 2 barvy’Pos(cervena) -- = 0 barvy’Val(0) -- = cervena 4 type pole is array (1 .. 10) of Natural; pole’First -- = 1 6 pole’Last -- = 10 pole’Range -- = 1 .. 10 8 type Byte is range -128 .. 127; for Byte’Size use 8; 10 Byte’Min -- = -128 Byte’Max -- = 127 12 F : Float; F’Ceiling; 14 F’Floor; F’Rounding; 16 F’Image -- Float -> String Float’Val -- String -> Float 18/52 Ada Vlákna v jazyce Java Ada: řídící struktury 1 if condition then statement; 3 else other statement; 5 end if; 7 case X is when 1 => 9 Walk_The_Dog; when 5 => 11 Launch_Nuke; when 8 | 10 => 13 Sell_All_Stock; when others => 15 Self_Destruct; end case; 17 Until_Loop : 19 loop X := Calculate_Something; 21 exit Until_Loop when X > 5; end loop Until_Loop; 23 for I in X’Range loop 25 X (I) := Get_Next_Element; end loop; 19/52 Ada Vlákna v jazyce Java Ada: výjimky package body Directory_Enquiries is 2 procedure Insert (New_Name : in Name; 4 New_Number : in Number) is 6 begin if New_Name = Old_Entry.A_Name then 8 raise Name_Duplicated; end if; 10 New_Entry := new Dir_Node’(New_Name, New_Number,); exception 12 when Storage_Error => raise Directory_Full; end Insert; 14 procedure Lookup (Given_Name : in Name; 16 Corr_Number : out Number) is 18 begin if not Found then 20 raise Name_Absent; end if; 22 end Lookup; 24 end Directory_Enquiries; 20/52 Ada Vlákna v jazyce Java Ada: generické typy 1 generic type Typ_Prvku is private; 3 with function "*" (X, Y: Typ_Prvku) return Typ_Prvku; function Umocni (X : Typ_Prvku) return Typ_Prvku; 5 function Umocni (X: Typ_Prvku) return Typ_Prvku is 7 begin return X * X; 9 end Umocni; 11 function Umocni_Mnozinu is new Umocni (Typ_Prvku => Mnozina.Prvek, "*" => Mocneni); 21/52 Ada Vlákna v jazyce Java Ada: konteinery Implementované pomocí generik Typy ◾ vektory ◾ dvojite spojene seznamy ◾ mapy ◾ mnoziny 22/52 Ada Vlákna v jazyce Java Ada: konteinery 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 => "="); 23/52 Ada Vlákna v jazyce Java Ada: konteinery 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 24/52 Ada Vlákna v jazyce Java 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) 25/52 Ada Vlákna v jazyce Java 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 26/52 Ada Vlákna v jazyce Java Přehled přednášky Ada Základy jazyka GNAT Vlákna v jazyce Java Viditelnost a synchronizace Ukončování vláken 27/52 Ada Vlákna v jazyce Java 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 28/52 Ada Vlákna v jazyce Java 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() 29/52 Ada Vlákna v jazyce Java 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 } } 30/52 Ada Vlákna v jazyce Java 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 31/52 Ada Vlákna v jazyce Java 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 32/52 Ada Vlákna v jazyce Java 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 33/52 Ada Vlákna v jazyce Java 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 31) 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 34/52 Ada Vlákna v jazyce Java 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 35/52 Ada Vlákna v jazyce Java 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 36/52 Ada Vlákna v jazyce Java 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 37/52 Ada Vlákna v jazyce Java 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 } 38/52 Ada Vlákna v jazyce Java 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 } 39/52 Ada Vlákna v jazyce Java 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 } 40/52 Ada Vlákna v jazyce Java Thead-safe data ad hoc ◾ zodpovědnost čistě ponechaná na implementaci ◾ nepoužívá podporu jazyka ◾ pokud možno nepoužívat 41/52 Ada Vlákna v jazyce Java 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 } } 42/52 Ada Vlákna v jazyce Java 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 } 43/52 Ada Vlákna v jazyce Java 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ší. 44/52 Ada Vlákna v jazyce Java 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 } 45/52 Ada Vlákna v jazyce Java 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 } } 46/52 Ada Vlákna v jazyce Java 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 } 47/52 Ada Vlákna v jazyce Java 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 – 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ě 48/52 Ada Vlákna v jazyce Java 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) 49/52 Ada Vlákna v jazyce Java 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) 50/52 Ada Vlákna v jazyce Java 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 51/52 Ada Vlákna v jazyce Java 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 } 52/52 Ada Vlákna v jazyce Java 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 } }