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 }
}