1/56
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
2012–02–28
2/56
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/56
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/56
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/56
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/56
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/56
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;
8/56
Ada Vlákna v jazyce Java
Ada: procedury, funkce
procedury: in, out a in out parametry
funkce: pouze in parametry, vrací hodnotu
function Funkce (A, B: Integer) return String
2 is
Retezec : Unbounded_String;
4 Prirozene_Cislo : Natural;
begin
6 Procedura (A, B, Retezec, Prirozene_Cislo);
Procedura (Retezec, Prirozene_Cislo);
8 Procedura (B => B, A => A, Retezec, Prirozene_Cislo);
return To_String (Retezec);
10 end Funkce;
12 type Callback_Procedury is access procedure (Id : Integer; T : String);
type Callback_Function is access function (Id : Natural) return Natural;
9/56
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;
10/56
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;
11/56
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;
12/56
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.
13/56
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
14/56
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
15/56
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;
16/56
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
17/56
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);
18/56
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
19/56
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;
20/56
Ada Vlákna v jazyce Java
Ada: řídící struktury
Until_Loop :
2 loop
X := Calculate_Something;
4 exit Until_Loop when X > 5;
end loop Until_Loop;
6
for I in X’Range loop
8 X (I) := Get_Next_Element;
end loop;
21/56
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;
22/56
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);
23/56
Ada Vlákna v jazyce Java
Ada: kontejnery
Implementované pomocí generik
Typy
◾ vektory
◾ dvojitě spojené seznamy
◾ (hash)mapy
◾ množiny
24/56
Ada Vlákna v jazyce Java
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 => "=");
25/56
Ada Vlákna v jazyce Java
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
26/56
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)
27/56
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
28/56
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
29/56
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
30/56
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()
31/56
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 }
}
32/56
Ada Vlákna v jazyce Java
Třída Thread
public static void main(String[] args) {
2 new MojeVlakno("vlakno1").start();
new MojeVlakno("vlakno2").start();
4 }
}
33/56
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
34/56
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
35/56
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
36/56
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 34)
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
37/56
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
38/56
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
39/56
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
40/56
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 }
41/56
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 }
42/56
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 }
43/56
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
44/56
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 }
}
45/56
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 }
46/56
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ší.
47/56
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 }
48/56
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 }
}
49/56
Ada Vlákna v jazyce Java
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 }
50/56
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 }
51/56
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 (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ě
52/56
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)
53/56
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)
54/56
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
55/56
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 }
56/56
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 }
}