Programování v jazyku Java vlákna a procesy

Podobné dokumenty
Procházka na provázku

Vlákna. První jednoduchý program s vlákny:

Vlákna. První jednoduchý program s vlákny:

30. Vlákna, jejich atributy, metody, organizace a stavy. Možnosti synchronizace. (A7B36PVJ)

VIII. Seminář Java VIII p.1/36

Definice třídy. úplná definice. public veřejná třída abstract nesmí být vytvářeny instance final nelze vytvářet potomky

Z. Kotala, P. Toman: Java ( Obsah )

Vláknové programování část V

Abstraktní datové typy: zásobník

Seznamy a iterátory. Kolekce obecně. Rozhraní kolekce. Procházení kolekcí

Příklad aplikace Klient/Server s Boss/Worker modelem (informativní)

JAVA V Vlákna Java, zimní semestr

Programovací jazyky s podporou vláken Java

Vlákno odlehčený proces kód vlákna, zásobník privátní ostatní sdíleno s dalšími vlákny téhož procesu

Předmluva k aktuálnímu vydání Úvod k prvnímu vydání z roku Typografické a syntaktické konvence... 20

4. ZÁKLADNÍ POJMY Z OBJEKTOVĚ ORIENTOVANÉHO PROGRAMOVÁNÍ

Obsah přednášky 7. Základy programování (IZAPR) Přednáška 7. Parametry metod. Parametry, argumenty. Parametry metod.

typová konverze typová inference

Algoritmizace a programování

JAVA. Krátke poznámky:

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

Pokud zadání nerozumíte nebo se vám zdá nejednoznačné, zeptejte se. Pište čitelně, nečitelná řešení nebudeme uznávat.

KTE / ZPE Informační technologie

IRAE 07/08 Přednáška č. 7. Začátek (head)

Programování v Javě I. Leden 2008

Programování v Javě I. Únor 2009

TŘÍDY POKRAČOVÁNÍ. Události pokračování. Příklad. public delegate void ZmenaSouradnicEventHandler (object sender, EventArgs e);

Vícevláknové aplikace

JAVA V jar Java, zimní semestr

7. přednáška - třídy, objekty třídy objekty atributy tříd metody tříd

Pokud zadání nerozumíte nebo se vám zdá nejednoznačné, zeptejte se. Pište čitelně, nečitelná řešení nebudeme uznávat.

RMI Remote Method Invocation

Multithreading vícevláknovost

Java Výjimky Java, zimní semestr

8 Třídy, objekty, metody, předávání argumentů metod

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

Správa paměti. Karel Richta a kol. Katedra počítačů Fakulta elektrotechnická České vysoké učení technické v Praze Karel Richta, 2016

Struktura programu v době běhu

C++ 0x aka C++11. Základním kamenem je třída std::thread

Konstruktory a destruktory

Úvod do programovacích jazyků (Java)

PREPROCESOR POKRAČOVÁNÍ

Procesy a vlákna - synchronizace

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

Stromy. Příklady. Rekurzivní datové struktury. Základní pojmy

Algoritmizace a programování

Seminář Java II p.1/43

Vytváření a použití knihoven tříd

Definice třídy. úplná definice. public veřejná třída abstract nesmí být vytvářeny instance final nelze vytvářet potomky

JSR tutorial 2 Transformace v JSR-184

Obsah přednášky 9. Skrývání informací. Skrývání informací. Zapouzdření. Skrývání informací. Základy programování (IZAPR, IZKPR) Přednáška 9

Java - výjimky. private void vstup() throws IOException {... }

OMO. 4 - Creational design patterns A. Singleton Simple Factory Factory Method Abstract Factory Prototype Builder IoC

Class loader. každá třída (java.lang.class) obsahuje referenci na svůj class loader. Implementace class loaderu

Výjimky. v C# a Javě

Generické programování

Typický prvek kolekce pro české řazení

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

Počítačové laboratoře bez tajemství aneb naučme se učit algoritmizaci a programování s využitím robotů CZ.1.07/1.3.12/

Definice třídy. úplná definice. public veřejná třída abstract nesmí být vytvářeny instance final nelze vytvářet potomky

Soubor jako posloupnost bytů

1. Téma 12 - Textové soubory a výjimky

Abstraktní třída a rozhraní

ZOS 9. cvičení, ukázky kódu. Pavel Bžoch

Semin aˇr Java V yjimky Radek Ko ˇc ı Fakulta informaˇcn ıch technologi ı VUT Unor 2008 Radek Koˇc ı Semin aˇr Java V yjimky 1/ 25

Pokud zadání nerozumíte nebo se vám zdá nejednoznačné, zeptejte se. Pište čitelně, nečitelná řešení nebudeme uznávat.

Úvod do programování - Java. Cvičení č.4

Řada programovacích jazyků nabízí prostředky pro řešení meziprocesové komunikace jako je synchronizace a řízení přístupu do kritické sekce.

Statické proměnné a metody. Tomáš Pitner, upravil Marek Šabo

Teoretické minimum z PJV

2) Napište algoritmus pro vložení položky na konec dvousměrného seznamu. 3) Napište algoritmus pro vyhledání položky v binárním stromu.

Cvičení 9 - Monitory. monitor m; var proměnné... procedure p; begin... end; begin inicializace; end;

Management procesu I Mgr. Josef Horálek

Datové struktury. alg12 1

součet cvičení celkem. známka. Úloha č.: max. bodů: skut. bodů:

Obsah přednášky. 12. Dokumentace zdrojového kódu Tvorba elektronické dokumentace UML. Co je diagram tříd. Ing. Ondřej Guth

Operační systémy. Přednáška 4: Komunikace mezi procesy

Java a XML. 10/26/09 1/7 Java a XML

7. Datové typy v Javě

Java Enum Java, zimní semestr ,2017 1

PŘETĚŽOVÁNÍ OPERÁTORŮ

Pavel Procházka. 3. prosince 2014

Pokročilé programování na platformě Java. Úvod

1. Programování proti rozhraní

IRAE 07/08 Přednáška č. 2. atr1 atr2. atr1 atr2 -33

boolean hasnext() Object next() void remove() Kolekce

Úvod do programovacích jazyků (Java)

20. Projekt Domácí mediotéka

Služba ve Windows. Služba (service) je program

Datové struktury obsah přednášky 1. Úvod 2. Třídy Type-wrapper (obalový typ) pro primitivní typy automatické převody 3. Automatické převody mezi

Principy objektově orientovaného programování

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

17. Projekt Trojúhelníky

Iterator & for cyklus

public class Karel { private int position; public boolean issmiling; public int getposition() { return position;

Základy jazyka C# Obsah přednášky. Architektura.NET Historie Vlastnosti jazyka C# Datové typy Příkazy Prostory jmen Třídy, rozhraní

29. Výjimky, jejich vznik, vyhození, odchyt a zpracování. (A7B36PVJ)

ALGORITMIZACE 2010/03 STROMY, BINÁRNÍ STROMY VZTAH STROMŮ A REKURZE ZÁSOBNÍK IMPLEMENTUJE REKURZI PROHLEDÁVÁNÍ S NÁVRATEM (BACKTRACK)

Programovací jazyk Java

OOPR_05. Případové studie

Transkript:

Evropský sociální fond Praha & EU: Investujeme do vaší budoucnosti Programování v jazyku Java vlákna a procesy BI-PJV Programování v jazyku Java Katedra teoretické informatiky Miroslav Balík Fakulta informačních technologií České vysoké učení technické

Procházka na provázku Program s mnoha metodami připomíná knósský labyrint (Labyrint = dům dvojbřité sekery) s mnoha sály, jimiž se protlouká statečný Theseus, jemuž pro šťastný návrat chytrá Ariadna dala klubíčko. Theseus pokaždé při vstupu do metody vlákno rozvíjí a při návratu z metody svíjí. V metodách Theseus provádí příkazy. V jávském labyrintu však může pobíhat najednou i více hrdinů a dokonce i rekurzivně neb je multithreadový. (Leč v jednom procesoru se v daném okamžiku pohybuje nanejvýš jeden tak jako v člověče nezlob se ). Každý Theseus má svoje vlákno - druhé konce třímá JVM v roli Ariadny, aby v případě nehody (...Exception ) mohla ony smolaře v labyrintu najít a z té šlamastiky vytáhnout. Totiž ani padlí hrdinové tam nesmějí zůstat. V labyrintu se mohou potulovat také démoni služební džinové, kteří se však vytratí, není-li tam již žádný živý opravdový hrdina. Také démoni jsou vláknem připoutáni k JVM. 2/40

Threadovy osudy isalive( )= false true completed interrupt( ) blocked state sleep( ) join( ) I/O end new start( ) runnable state acquires lock lock state lock pool I/O start CPU scheduler running state yield( ) i n o hr interrupt( ) sets flag only d ze c n sy notify( ) interrupt( ) run( ) { dead wait(...) must have lock and then releases lock wait state wait pool 3/40

Přidělování času JVM scheduler přiděluje CPU čas nespecifikovaným způsobem některému vláknu s nejvyšší prioritou, pokud ono je ve stavu runnable. priority CPU time scheduler MAX 10 NORM 5 MIN 1 T8 T6 T7 T5 T3 T2 T4 T10 T9 T1 T6 state: new runnable running blocked dead 4/40

Vlákno = thread = lightweight process = task... Vlákno není program je to jakýsi výpočtář, tj. objekt vykonávající činnost. K provedení výpočtu je nezbytný alespoň jeden výpočtář, který má: k dispozici program tedy předpis postupu ( metody, konstruktory ), přístupná data, což jsou atributy tříd, objektů, parametry, proměnné, čas na práci. Vlákno si musí dynamicky pamatovat: 1.v které metodě či konstruktoru se právě nalézá a kam se pak vrátit, 2.své lokální proměnné (obé je v aktivačním záznamu na zásobníku), 3.adresu aktuálního příkazu v aktuální metodě ( program counter ). Výpočet končí, skončí-li všechna nedémonická vlákna. Otázka, jak je vlákno dlouhé, není nesmyslná: jeho délku lze chápat jako momentální počet aktivačních záznamů na zásobníku. 5/40

Thread a Runnable JVM scheduler dodává CPU čas tím, že zavolá metodu run( ) objektů typu java.lang.thread, zařazených do prioritních front jsou-li ve stavu runnable-running. V těle metody public void run( ) se definuje požadované chování vlákna lze volat též metody libovolného objektu či třídy. Interfejs java.lang.runnable obsahuje pouze metodu: public void run( ); Thread je konkrétní třída implementující Runnable skoro prázdnou, metodou umožňující předat řízení metodě run v cílovému objektu takto: public void run( ) { if ( target!= null ) target.run( ); V potomcích Threadu se metoda run( ) přepisuje na neprázdnou definující požadovanou činnost vlákna. 6/40

Metoda run( ) Metoda public void run( ) { třídy Thread definuje, co má vlákno dělat. Volá ji JVM a nikoli programátor - ten pouze vlákno odstartuje metodou start( ), čímž se vlákno přidá do stromu vláken a do fronty na CPU čas. Tím se vlákno oživí - isalive( ) vrací true. Metoda run( ) typicky obsahuje cyklus, který probíhá, pokud jiné vlákno nenastaví condition na false. Tak je zajištěno, že vlákno dokoná definovaným způsobem ( zavrženou metodou stop( ) nikoli ). 7/40

Metoda run( ) class MyThread extends Thread { boolean condition = true; // počáteční nastavení public void run( ) { while ( condition ) {... // požadovaná činnost.. // případný epilog // smrtící závorka nebo return kdekoli v metodě 8/40

Třída Thread má přetížené konstruktory s kombinacemi těchto parametrů: Runnable target - přesměrování dodávky CPU do určeného objektu, který implementuje interfejs Runnable. String name - jméno vlákna (chybí-li, dosadí se systematické jméno). ThreadGroup group - přiřazení vlákna do skupiny, změna nemožná. Skupinu vláken lze ovládat najednou. long stacksize - nastavení velikosti zásobníku. Má vnitřní enum Thread.State pro stavy: NEW, RUNNABLE, BLOCKED, WAITING, TIME_WAITING, TERMINATED. A vnitřní interfejs Thread.UncaughtExceptionHandler definující void uncaughtexception( Thread t, Throwable e ) Nedémon defaultně vytváří nedémona, démon démona. Démoničnost je nastavitelná jen před spuštěním dotyčného vlákna. 9/40

Statické metody Thread currentthread( ) - odkaz k běžnému vláknu. int activecount( ) - počet aktivních vláken ve skupině tohoto vlákna. void dumpstack( ) - výpis zásobníku tohoto vlákna. boolean holdslock( Object o ) - má vlákno zámek objektu? boolean interrupted( ) - bylo toto vlákno přerušeno? A výmaz příznaku. native void sleep( long msec ) throws InterruptedException uspání. Při předčasném probuzení jiným vláknem vyhodí výjimku. void yield( ) - vlákno přejde ze stavu running do runnable, tj. zřekne se zbytku momentálního přídělu času. int enumerate ( Thread[ ] tarr ) do určeného pole zkopíruje všechna aktivní vlákna skupiny běžného vlákna a jejích podskupin. Thread.UncaughtExceptionHandler getdefaultuncaughtexceptionhandler( ) 10/40

Nestatické metody void run( ) - definice funkcionality. void start( ) - aktivace, tj. oživení ( mrtvé vlákno nelze oživit ). boolean isalive( ) je živé? int getname( ) / void setname( String name ) - getter/setter jména. int getpriority( ) / void setpriority( int priority ) - getter/setter priority. Thread.State getstate( ) stav pro monitoring ne pro synchonizaci. ThreadGroup getthreadgroup( ) skupina do které vlákno patří. boolean isdaemon( ) - test démona. void setdaemon( boolean on ) - nastavení démona/nedémona. void interrupt( ) - přerušení vlákna. boolean isinterrupted( ) - bylo ono vlákno přerušeno? Příznak nezměněn. void join( ) throws InterruptedException - čekání na konec jiného vlákna. void join( long msec ) throws InterruptedException s maximem čekání. void setuncaughtexceptionhandler(thread.uncaughtexceptionhandler h) Thread.UncaughtExceptionHandler getuncaughtexceptionhandler( ) 11/40

Způsoby použití S vlákny lze pracovat dvojím způsobem: 1. Definovat potomka třídy Thread, v něm překrýt metodu run( ) pro požadovanou funkcionalitu, zkonstruovat objekt a ten aktivovat zděděnou metodou start( ). Toto řešení se hodí jen pro velmi jednoduché případy. 2. Definovat nějakou třídu implementující interfejs Runnable a v ní překrýt metodu run( ) pro žádanou funkcionalitu. Zkonstruovat příslušný objekt. Zkonstruovat objekt Thread s parametrem Runnable odkazující na onen objekt. Pak odstartovat objekt Thread. Toto řešení je obecnější, Runnable objekt ( jenž není vláknem ) může být složitý, neboť může výhodně dědit od bohaté třídy. 12/40

První způsob: Tik class Tik extends Thread { public void run( ) { // překrytá metoda Threadu try { while( true ) { System.out.println( Tik ); sleep( 1000 ); // static method catch( InterruptedException ex ) { spuštění zkráceně: new Tik( ).start( ); spuštění rozepsaně: Tik t = new Tik( ); t.start( ); Protože Tik je Thread, startem se zařadí do fronty na CPU čas. 13/40

Druhý způsob: Tak class Tak extends Orloj implements Runnable { public void run( ) { // překrytá metoda Runnable try { while( true ) { System.out.println( Tak ); Thread.sleep( 1000 ); // statická methoda catch( InterruptedException ex ) { spuštění zkráceně: new Thread( new Tak( ) ). start( ); spuštění rozepsaně: Runnable r = new Tak( ); new Thread( r ). start( ); Tak není Thread, avšak má metodu run, kterou zavolá nepřekrytá metoda Threadu, neboť Tak je její target. 14/40

Tik versus Tak java.lang. CPU time priority queue Object Tik Thread call java.lang. java.lang. Thread run() { static sleep() Tak Runnable Orloj run() ; Tik Tak run() { run() { class return interface extends implements Tak object 15/40

Sdílení dat mezi vlákny public class Vlakno implements Runnable{ int sdilena = 0; public void run() { for(int i = 0; i<100;i++, sdilena++){ System.out.printf("Sdilena:%5d, i:%5d%n", sdilena,i); public static void main(string[] args) { Vlakno v1 = new Vlakno(); Thread t1 = new Thread(v1), t2 = new Thread(v1); //obě vlákna musí být nad stejným objektem typu Runnable - zde v1 t2.start(); t1.start(); 16/40

Sdílení dat mezi vlákny public class Vlakno implements Runnable{ int sdilena = 0; public void run() { for(int i = 0; i<100;i++, sdilena++){ System.out.printf("Sdilena:%5d, i:%5d%n", sdilena,i); public static void main(string[] args) { Vlakno v1 = new Vlakno(); Thread t1 = new Thread(v1), t2 = new Thread(v1); //obě vlákna musí být nad stejným objektem typu Runnable - zde v1 t2.start(); t1.start(); Sdilena: Sdilena: Sdilena:... Sdilena: Sdilena: Sdilena:... Sdilena: Sdilena: Sdilena: Sdilena:... 0, i: 1, i: 2, i: 0 1 2 14, i: 14 0, i: 0 15, i: 15 109, i: 110, i: 94, i: 112, i: 98 99 11 12 Sdilena: 197, i: 97 Sdilena: 198, i: 98 Sdilena: 199, i: 99 17/40

Interakce vláken Vlákna mohou běžet na sobě nezávisle, mohou se vzájemně hledat, testovat, [ne]koordinovaně ovlivňovat anebo mohou spolupracovat. Metody pro: hledání: currentthread( ), activecount( ), getthreadgroup( ),... testování: isalive( ), isdaemon( ), interrupted( ), isinterrupted( ),... ovlivňování: start( ), nastavení proměnných, interrupt( ), setpriority( ),... navazování: join( ) spolupráci: wait( ), notify( ), notifyall( ) tyto metody vyžadují synchronizaci pomocí synchronized. 18/40

Interupt Metoda t.interrupt( ) sama nezaručuje zastavení vlákna t - záleží na stavu vlákna t. running : žádná vyjímka se nevyhodí, jen mu nastaví jeho příznak přerušení (flag). Je na tomto, aby si svůj flag evetuálně zkontroloval a něco udělal. Pokud později přejde do stavu waiting nebo sleeping, předtím než metoda interrupted( ) příznak shodí, vyhodí se InterruptedException a příznak se shodí. waiting/sleeping : Vlákno přejde do runnable stavu a jakmile poběží vyhodí se InterruptedException. Příznak přerušení není nastaven. runnable : nic se neděje do té doby než přejde do running stavu dále viz první bod. 19/40

Join Metoda t.join( timeout ) blokuje běžné vlákno pokud je vlákno t živé, nejdéle však po dobu timeout. Je-li timeout == 0 je doba nekonečná. Metoda t.join( ) je ekvivalentní t.join(0). To umožňuje běžnému vláknu vyčkat a pak navázat na výsledky činnosti dokončení práce vlákna t. Neodstartované vlákno t je neživé a tedy neblokuje běžné. Na ukončení vlákna může čekat více vláken. Vlákna se nijak vzájemně nenavazují ( tj. nesloučí se v nějaké jediné každé samostatně doběhne ), navazuje se jejich práce. 20/40

Pilný strýc a líný synovec Vlákno-synovec lajdá (je blokován) do doby, než vlákno-strýc dokončí svůj úkol (vydělat sto milionů) - čili až zemře. Dědictví si však dlouho neužije. Synovec může zjistit strýcův stav metodou isalive( ). Je-li nedočkavý, zavolá metodu join( timeout ) - leč získá jen část peněz. public class Nephew { static Uncle u = new Uncle( ); public static void main( String[ ] args ) throws InterruptedException { u.join( ); // blocked System.out.println( u.money ); // heritage class Uncle extends Thread { int money = 0; public Uncle( ) { this.start( ); public void run( ) { while ( ( ++money ) < 100000000 ); // work 21/40

Nesynchronizace v hanebné bance public class Test { public static void main( String[ ] args ) { new Clerk( ).start( ); new Clerk( ).start( ); for ( int i=1; true; i++ ) System.out.println( i+ ".:" + Accounts.dump( ) ) ; class Accounts { static long a1=0, a2 = 1000; static void move( int x ) { a1 -= x; a2 += x; // zdroj problému static String dump( ) { return a1+ " + " +a2+ " = " +(a1+a2); class Clerk extends Thread { public void run( ) { while ( true ) Accounts.move( ( int ) ( ( Math.random( ) - 0.5 ) *100 ) ); 22/40

Synchronizace Synchronizace brání vstupu více vláken do tzv. kritických sekcí, aby jejich nekoordinovaná činnost nezpůsobila chaos v hodnotách atributů. (Obdobou kritické sekce je autoblok na železnici.) Klíčové slovo synchronized u metody či bloku definuje kritickou sekci. Kritických sekcí může být více a mohou být i do sebe vložené. Mají být co nejkratší, aby nesnižovaly průchodnost programu. Každý objekt má jediný zámek ( intrinsic lock, monitor lock či též monitor ). Vlákno, které zámek získá, vstoupí do kritické sekce a zamkne objekt, po jejím opuštění se zámek vrátí objektu, čímž se objekt odemkne. Vlákno může získat více zámků od různých objektů. Vlákno bez patřičného zámku ke kritické sekci do ní vstoupit nemůže a je přeřazeno ze stavu running do čekárny lock poolu. Vrácený zámek JVM přidělí nedeterministicky některému příslušnému vláknu z lock poolu a přeřadí ho do stavu runnable. 23/40

Synchronizace class X {... synchronized... method1 (... ) { // Synchronizovaná metoda method2 (... ) { // Nesynchronizovaná metoda synchronized( o1 ) { // Synchronizované bloky synchronized( o2 ) { // o1, o2 jsou reference k nějakým objektům // nebo this nebo Z.class anebo k poli Atributy jejichž hodnoty se mění mají být private. Statické synchronizované metody využívají zámek třídy. Konstruktory a inicializátory provádí právě jedno vlákno. 24/40

Spolupráce Vlákna spolupracující na nějakém objektu, musejí být koordinována tak, aby nepatřičně nezasahovala do společně přístupných dat. Příkladem je PC-problém ( Producer Consumer ): Producenti se snaží dodat nějaké objekty do skladu. Konzumenti se snaží objekty ze skladu odebrat. Sklad má určitou kapacitu a je-li: - plný, producenti čekají na volné místo. - prázdný, konzumenti čekají na dodávku. Žádný objekt se nesmí ztratit. Tentýž objekt nelze odebrat dvakrát. Producenti a konzumenti se navzájem neznají a nekomunikují spolu. Producenti a konzumenti jsou upozorňováni o změnách stavu skladu. Sklad musí být dobře střežen: důležité proměnné musejí být private. Přístup k nim je možný jen přes synchronizované metody. Přístup do skladu má vždy pouze jeden producent anebo konzument. 26/40

PC - problém Producers Store Consumers lock synchronized put synchronized get 27/40

Metody wait a notify Koordinovaný přístup ke sdíleným datům se zajišťuje jednak všeobecnými finálními metodami wait a notify a jednak čekárnami wait pool a lock pool. Volat wait a notify může jen vlákno vlastnící zámek k objektu, tj. jen uvnitř kritické sekce, jinak dojde k IllegalMonitorStateException. Čekáním vlákna ve wait poolu na změnu: - wait( ) - vlákno čeká až... - wait( long timeout ) čeká až..., leč čeká nejdéle zadanou dobu. Obě metody wait odemykají objekt a vracejí zámek. Vlákno se převede z wait do lock poolu též zavoláním metody interrupt( ), přičemž se vyhodí výjimka InterruptedException. Upozorněním jiného vlákna, že došlo ke změně podmínek. Vlákno (či vlákna) se z wait do lock poolu se převede metodou: - notify( ) - JVM nedeterministicky převede jedno vlákno. - notifyall( ) - JVM převede všechna vlákna. Vlákna v lock poolu čekají na přidělení zámků k příslušným objektům. 28/40

Producer Consumer Problem public class PCProblem { public static void main(string[ ] args) throws Exception { Box b = new Box( ); Producer p = new Producer(b); p.start( ); Consumer c = new Consumer(b); c.start( ); p.join( ); c.join( ); b.print( "END" ); 29/40

Producer Consumer Problem class Box { // Box pro jeden objekt private Object x; public void print( String r ) { System.out.println( r+" Box has "+x ); synchronized void put( Object z ) { while ( x! = null ) try { wait( ); catch ( InterruptedException ex ) { notifyall( ); x = z; print( "PUT" ); synchronized Object get( ) { while ( x == null ) try { wait( ); catch ( InterruptedException ex ) { notifyall( ); Object z = x; x=null; print( "GET" ); return z; 30/40

Producer Consumer Problem class Producer extends Thread { Box b; Producer( Box b ) { this.b=b; public void run( ) { for ( int i = 0; i < 10; i++ ) { b.put( new Integer( i ) ); try { sleep( ( int )( Math.random( )*1000 ) ); catch ( InterruptedException ex ) { 31/40

Producer Consumer Problem class Consumer extends Thread { Box b; Consumer( Box b ) { this.b=b; public void run( ) { for ( int i = 0; i < 10; i++ ) { System.out.println( ( Integer ) b.get( ) ); try { sleep( ( int ) ( Math.random( )*1000 ) ); catch ( InterruptedException ex ) { 32/40

Uvíznutí (deadlock) Dva chudí lešetínští kováři v mají jedno společné nářadí: kladivo a kleště. Nedohodnou-li se, dojde časem k zlobně umrtvujícímu nicnedělání, tzv. deadlocku čili smrtelnému zaklesnutí. Přihodí se to takto: První uchopil kladivo a potřebuje ještě kleště. Mezitím však druhý uchopil kleště a čeká až bude kladivo volné. Nikdo to za ně nevyřeší a tak oba čekají a čekají... čímž živnosti uvíznou a oba ještě více zchudnou - a šafářovic Andulka se nedočká. Přitom stačí rozumná dohoda - budeš-li potřebovat oba nástroje: Nejdříve uchop kladivo a teprve pak sháněj kleště. Pracuj. Pak nejdříve pusť kleště, potom kladivo. Ta zaručuje momentálnímu držiteli kladiva, že kleště budou časem volné. Kovářů může být ve městě i více. 33/40

Proti uvíznutí Programátor znemožní uvíznutí takto: synchronized ( hammer ) { synchronized ( tongs ) {... // work Více nářadí lze vložit do synchronizované kolekce či do pole. ( Pole je svou podstatou synchronizovaný objekt. ) private Collection tools = new Vector( ); tools.add( hammer ); tools.add( tongs ); tools.add(...); // fill tools synchronized ( tools ) { Object x = tools.get(...);... // work 34/40

Strom vláken umožňuje třída ThreadGroup. Strom obsahuje všechna živá vlákna. ThreadGroup( ThreadGroup parent, String name ) konstruktor. int activecount( ) odhad počtu vláken ve skupině. int activegroupcount( ) odhad počtu skupin ve skupině. int enumerate( Thread[ ] ) výčet vláken ve skupině. int enumerate( ThreadGroup[ ] ) výčet skupin vláken ve skupině. ThreadGroup getparent( ) reference k nadskupině. boolean parentof( ThreadGroup g ) test příslušnosti k podstromu g. void list( ) výpis skupiny. void interrupt( ) přerušení všech vláken podstromu. boolean isdaemon( ) je démonická skupina? void setdaemon( boolean on ) démonizace všech vláken skupiny. void setmaxpriority( int pri ) nastavení pro další členy skupiny. void destroy( ) zrušení prázdného podstromu. void uncaughtexception( Thread t, Throwable e ) odchyt nechyceného 35/40

Strom vláken system Reference Handler 10 main main 5 Finalizer 8 MyGroup skupina MyThreadA 5 Signalizer Dispatcher 9 MyThreadB 5 Attach Listener 5 daemon 36/40

Ukončení běhu vlákna Normální: metoda run objektu typu Thread skončí návratem do JVM. Objekt je vyřazen ze stromu vláken a z fronty na CPU čas. Vlákno je mrtvé tj. metoda isalive( ) vrací false. Nelze ho oživit. Pokud existuje reference, objekt je dostupný. Abnormální: následkem neodchyceného objektu (Error nebo RuntimeException). Vlákno může definovat Thread.UncaughtExceptionHandler, jinak se zavolá metoda uncaughtexception( ) definovaná v typu ThreadGroup. Ta defaultně volá tutéž metodu v rodičovském objektu. Metody uncaughtexception volá JVM. Násilné: pomocí zavrženíhodné metody stop( ), což je [sebe]vražda následkem ThreadDeath chyby, což může vést k nedozírným následkům. Doporučuje se nepoužívat. 37/40

Časové spouštění úloh umožňují třídy java.util.timer a abstraktní java.util.timertask. Timer( ) konstruktor. Timer( boolean isdaemon ) konstruktor pro démona. void schedule(... ) naplánuje spuštění úkolu. void scheduleatfixedrate(... ) spouštění s pevným intervalem. - tyto metody mají parametry: TimerTask task naplánovaný úkol. Date firsttime datum a čas prvního spuštění. long delay zpoždění pro první spuštění. long period perioda dalších spuštění. void cancel( ) ukončí činnost objektu i naplánované úkoly. Uplynul-li již moment spuštění, spustí se ihned. 38/40

Časové spouštění úloh Abstraktní třída java.util.timertask má: protected TimerTask( ) konstruktor. public void cancel( ) ukončí naplánovaný úkol. public long scheduledexecutiontime( ) čas posledního spuštění. public abstract void run( ) definice činnosti. Timer t = new Timer( ); t.schedule( new TTA( ), 10000 ); t.scheduleatfixedrate( new TTB( ), 5000, 500 ); class TTA extends TimerTask{ public void run( ) { System.out.println( A ); class TTB extends TimerTask{ public void run( ) { System.out.println( B ); 39/40

Jak JVM spouští aplikaci Při spuštění java T aa bb ccc systémové vlákno, získá informace z cmd řádky, vytvoří ThreadGroup main a v ní vlákno main s prioritou 5, odstartuje ho. Toto vlákno prochází postupně statickými inicializátory. Leč neodchycená výjimka způsobí ExceptionInInitializerError. V normálním případě vlákno main projde do metody T.main. class... implements Runnable { public void run( ) { try { // call all static initializers // call T.main( args ) catch ( Throwable ex ) { ex.printstacktrace( ); finally { /* release resources */ // tiskne parte 40/40