Procházka na provázku Program s metodami připomíná knósský labyrint se sály, jimiž se protlouká statečný Theseus, jemuž pro šťastný návrat chytrá Ariadna.

Slides:



Advertisements
Podobné prezentace
A1PRG - Programování – Seminář Ing. Michal Typová konverze, oblast platnosti, paměťové třídy 9 Verze
Advertisements

(instance konkrétní třídy)
Orbis pictus 21. století Tato prezentace byla vytvořena v rámci projektu.
Programovací jazyk C++
10. Dynamické datové struktury
Pole, ukazatele a odkazy
ÚVOD DO CPP 7 Dědičnost - pokračování
Operační systémy. OPERAČNÍ SYSTÉMY pomoc operátorovi, podpora vlastností reálného času, víceuživatelských a více úlohových systémů.
PJV151 Vnořené a vnitřní členy mohou být členy tříd a interfejsů. Je-li X obalem Y a Y je obalem Z, pak Z získá jméno X$Y$Z - kompilací vzniknou classy.
Počítače a programování 1. Obsah přednášky Výjimky - základní typy výjimek Způsoby zpracování výjimek.
Programování v C++ Cvičení.
J a v a Začínáme programovat Lucie Žoltá metody, objekty, konstruktor.
Objekty v CLIPSu RNDr. Jiří Dvořák, CSc.
Fronty (Queue) v JDK 1.5 (1.6) Java.vse.cz.
State. State – kontext a problém Kontext  chování objektu má záviset na jeho stavu, který se typicky mění za běhu Neflexibilní řešení  metody obsahují.
Páté cvičení Dědičnost Interface Abstarktní třídy a metody
13AMP 6. přednáška Ing. Martin Molhanec, CSc.. Co jsme se naučili naposled Synchronizace procesů Synchronizace procesů Producent-Konzument Producent-Konzument.
C# - Exceptions (výjimky)
Objektové programování
Podpora vláken a jejich synchronizace v jazyce C# Jan Kučera Jan Mittner Petr Effenberger 4IT353 Klient/server aplikace v Javě.
Jedenácté cvičení Vlákna. Java cv112 Vlákna Operační systém Mutitasking – více úloh se v operačním programu vykonává „současně“ Java Multithreading -
PRÁCE S VLÁKNY A APLIKAČNÍ DOMÉNY V.NET FRAMEWORK APLIKACÍCH Architektura technologie.NET Jan Martinovič, FEI - Katedra Informatiky.
6. cvičení Polymorfismus
Počítače a programování 1
JavaScript Podmínky, cykly a pole.
13AMP 2. přednáška Ing. Martin Molhanec, CSc.. Stav procesu (kontext) Stav procesu je úplná informace, kterou je nutné uschovat při přerušení procesu,
KIV/PPA1 cvičení 8 Cvičící: Pavel Bžoch. Osnova cvičení Objekty v Javě Třída Konstruktor Metody Metody a proměnné třídy x instance Program sestávající.
Algoritmizace a programování Objektově orientované programování - 16 Mgr. Josef Nožička IKT Algoritmizace a programování
2 Ing. Jan Keprt Centrální správa uživatelů 3 Jak to bylo dosud Bylo třeba nastavení uživatelů provést zvlášť, v každém modulu samostatně. Uživatel si.
C# - předávání parametrů Centrum pro virtuální a moderní metody a formy vzdělávání na Obchodní akademii T.G. Masaryka, Kostelec nad Orlicí.
13AMP 3. přednáška Ing. Martin Molhanec, CSc.. Co jsme se naučili naposled I. Co je to kontext úlohy Co je to kontext úlohy Task switching (přepnutí úlohy)
JavaScript Funkce.
Dědičnost - inheritance dědičnost je jednou z forem znovupoužitelnosti dědičnost je jednou z forem znovupoužitelnosti B A Třída A je předkem třídy B Třída.
10. Dynamické proměnné Dynamická proměnná se nezavádí deklarací proměnných, ale vzniká za běhu programu provedením speciálního příkazu. Nemá přidělen žádný.
7. Typ soubor Souborem dat běžně rozumíme uspořádanou množinu dat, uloženou mimo operační paměť počítače (na disku). Pascalský soubor je abstrakcí skutečného.
Richard Lipka Department of Computer Science and Engineering Faculty of Applied Sciences University of West Bohemia, Pilsen, Czech Republic 1.
13/04/20151 Multitasking Schopnost operačního systému mít spuštěno více programů současně Operační systém používá hardwarové hodiny a každému běžícímu.
Šesté cvičení Výjimky Balíky.
Zablokování (deadlock, smrtelné objetí, uváznutí)
Netrvaloppa21 Vytvořte třídu Student pro reprezentaci struktury student na ZČU. Atributy třídy budou fakulta a osobniCislo. Název třídy: Student proměnné.
Databázové systémy 2 Cvičení č. 5 Fakulta elektrotechniky a informatiky Univerzita Pardubice.
3. konzultace (5 hodin) Studijní materiály najdete na adrese:
13AMP 4. přednáška Ing. Martin Molhanec, CSc.. Co jsme se naučili naposled Problém sdílených zdrojů Problém sdílených zdrojů Co je to kritická sekce Co.
PJV031 Přetypování (casting) Objekty, atributy, lokální proměnné, parametry a návratové hodnoty metod mají definovaný, neměnný typ. Jsou dva druhy typů:
Počítače a programování 1 7.přednáška. Základy Pole ve třídách a metodách Pole Arrays.
FEL Komunikátor. Memory Leak program konsumuje operační paměť, kterou neumožňuje uvolnit o uvolnění paměti stará Garbage Collector ▫plně v režii Java.
Pokročilé programování v C++ (část B)
Jazyk C A0B36PRI - PROGRAMOVÁNÍ Část II.
Základy operačních systémů Meziprocesová komunikace a synchronizace Jakub Yaghob.
Strategy. Motivace Různé algoritmy pro stejnou akci Hromada kódu v mnoha podmínkách Důsledky  Komplexnost  Špatná čitelnost  Těžká správa kódu  Těžka.
Vývoj informačních systémů Námět na praktické cvičení Klient – Server (nepovinné)
Uvedení autoři, není-li uvedeno jinak, jsou autory tohoto výukového materiálu a všech jeho částí. Tento projekt je spolufinancován ESF a státním rozpočtem.
PJV15 1 Vnořené ( nested ) a vnitřní ( inner ) členy Třídy či interfejsy mohou být členy tříd či interfejsů. Je-li X obalem Y a Y obalem Z, pak Z získá.
Služby Windows Autorem materiálu a všech jeho částí, není-li uvedeno jinak, je Ing. Libor Otáhalík. Dostupné z Metodického portálu ISSN: 
Úvod do C# - OOP Jaroslav BURDYS 4IT.
Programovací jazyk C++
Soubor Soubor v informatice označuje pojmenovanou sadu dat uloženou na nějakém datovém médiu, se kterou lze pracovat nástroji operačního systému jako.
Y36PJC Programování v jazyce C/C++
Generické typy jsou třídy či interfejsy deklarující tzv. typové parametry jimiž: systematizují typovou kontrolu kompilátorem, vyjadřují jasněji smysl,
Typový příklad 3 – zadání 1
Polymorfismus = Mnohotvarost
Příkazy cyklu (1) Umožňují vícekrát (nebo ani jednou) pro-vést určitý příkaz Jazyk C rozlišuje příkaz cyklu: s podmínkou na začátku: obecný tvar: while.
Dynamické proměnné (1) Proměnné, jejichž počet a (nebo) velikost pa-měti využívané těmito proměnnými se v prů-běhu programu mění Dynamické proměnné lze.
Reflexe jako introspekce
Práce s procesy Centrum pro virtuální a moderní metody a formy vzdělávání na Obchodní akademii T.G. Masaryka, Kostelec nad Orlicí Autor:
C# přehled vlastností.
Cyklus for (1) Obecný tvar: for (výraz1; výraz2; výraz3) příkaz
NÁZEV ŠKOLY: S0Š Net Office, spol. s r.o., Orlová-Lutyně
Výčtové typy ( Java 5 ) Výčtové typy jsou speciální třídy zavedené pro větší bezpečí a pohodlí. V nejjednodušší variantě se definují příkladmo takto:
Monitor Object 1.
Transkript prezentace:

Procházka na provázku Program s metodami připomíná knósský labyrint se sály, jimiž se protlouká statečný Theseus, jemuž pro šťastný návrat chytrá Ariadna dala klubíčko. Theseus vždy při vstupu do metody vlákno rozvíjí a při návratu z metody svíjí. V metodách a konstruktorech provádí příkazy. V jávský labyrint je multithreadový čili se v něm potuluje ( i rekurzivně ) najednou více postav: Hrdinové i démoni ( tj. služební džinové ) – každý z drží jeden konec svého vlákna. Druhé konce třímá JVM v roli Ariadny, aby je v případě nehod ( Throwable ) mohla z labyrintu vytáhnout – pokud se ovšem vlákno nepřetrhlo – to, aby v něm zranění a padlí nezůstali. ( Leč v jednom procesoru se v daném okamžiku pohybuje nanejvýš jeden – tak jako v “člověče nezlob se“. ) Jakmile všichni hrdinové opustí labyrint, JVM vypudí i démony, zruší labyrint a sebe ( JVM = Ariadna spáchá sebevraždu ) – tím aplikace skončí. Nesmutněme, získali jsme výsledky i zkušenosti a můžeme ji reinkarnovat. PJV06

Osud state state state state state BLOCK completed interrupt( ) false isAlive( ) true BLOCK state completed interrupt( ) I/O end sleep(…) join(…) I/O start CPU scheduler start( ) run( ) {…} RUNNABLE state RUNNING state NEW DEAD interrupt( ) yield( ) interrupt( ) sets flag only sets flag only synchronized wait(…) acquires object’s lock must have lock then releases it notify( ) notifyAll( ) timeout interrupt( ) LOCK state WAIT state synchronization object’s lock pool synchronization object’s wait pool PJV06

Přidělování času CPU time scheduler 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 T8 T6 MAX 10 CPU time scheduler NORM 5 T7 T5 T2 MIN 1 T3 T4 T9 T6 T10 T1 vlákna ve stavu: NEW RUNNABLE RUNNING BLOCKED DEAD PJV06

Vlákno = thread = lightweight process = task ... Vláknem je pouze objekt typu java.lang.Thread. 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ň jedno vlákno, které má: k dispozici program – tedy předpis postupu ( metody, konstruktory ), přístup k datům ( atributy tříd, objektů, parametry, proměnné ) příděly času na práci. Vlákno si musí dynamicky pamatovat: v které metodě či konstruktoru se právě nalézá a kam se pak vrátit, své lokální proměnné ( obé je v aktivačním záznamu na zásobníku ), adresu aktuálního příkazu v aktuální metodě ( program counter ). Výpočet končí, skončí-li všechna nedémonická vlákna. Délku vlákna lze chápat jako momentální počet aktivačních záznamů na zásobníku. PJV06

java.lang: Thread a Runnable JVM scheduler dodává vláknu CPU čas skrze metodu run( ) objektů typu Thread, zařazených do prioritních front, jsou-li ve stavu running. V těle metody public void run( ) se definuje požadované chování vlákna – přičemž lze volat též metody libovolného objektu či třídy. Interfejs 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: Runnable target ; // initialized in constructor eventually public void run( ) { if ( target != null ) target.run( ); } V potomcích Threadu se metoda run( ) překrývá a v ní je určena požadovaná činnost. PJV06

Metoda run( ) Metoda public void run( ) { … } v typu Thread definuje činnost vlákna. Volá ji JVM - ne programátor – ten jen vlákno odstartuje metodou start( ), čímž JVM přidá vlákno do stromu vláken a do fronty na CPU čas. Tím se vlákno oživí – metoda public final boolean isAlive( ) pak vrací true. Metoda run( ) typicky obsahuje cyklus, který probíhá, pokud jiné vlákno nenastaví condition na false. Tak vlákno dokoná práci definovaným způsobem ( zavrženou metodou stop( ) nikoli ). 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ě PJV06

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 – viz třída ThreadGroup. long stackSize - nastavení velikosti zásobníku. Má vnitřní enum Thread.State pro stavy v rámci JVM (ordinal 0 .. 5): NEW, RUNNABLE, BLOCKED – čeká na zámek, WAITING – čeká na akci, TIME_WAITING – čeká dočasně na akci, TERMINATED. Má 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. PJV06

Statické metody Thread currentThread( ) - odkaz k běžnému vláknu. int activeCount( ) - počet aktivních vláken ve skupině tohoto vlákna. native 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 msec < 0 vyhodí IllegalArgumentException. Při přerušení spánku jiným vláknem vyhodí výjimku. native 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. PJV06

Nestatické metody void run( ) - definuje funkcionalitu. void start( ) - aktivace, tj. oživení ( mrtvé vlákno nelze oživit ). final native boolean isAlive( ) – je už či ještě živé ? long getId( ) – stálý identifikátor vlákna > 0 ( znovupoužitelný ) final String getName( ) / void setName( String name ) – ovládání jména. final int getPriority( ) / void setPriority( int priority ) - ovládání priority. Thread.State getState( ) – stav - pro monitoring - ne pro synchronizaci. 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šit ono vlákno, záleží na stavu. boolean isInterrupted( ) - bylo ono vlákno přerušeno? Příznak nemění. final void join( … ) throws InterruptedException - čekání na konec jiného vlákna, případně s vymezením času. PJV06 ALG

Metody sledování vlákna static void dumpStack( ) - výpis zásobníku tohoto vlákna do System.err . static Map<Thread, StackTraceElement[ ]> getAllStackTraces( ) - mapa všech živých vláken StackTraceElement[ ] getStackTrace( ) – pole prvků zásobníku void setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler h) Thread.UncaughtExceptionHandler getDefaultUncaughtExceptionHandler( ) Thread.UncaughtExceptionHandler getUncaughtExceptionHandler( ) void setContextClassLoader ( ClassLoader cl ) - nastavení PJV06 ALG

Způsoby použití S vlákny lze pracovat dvojím způsobem: 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ž však není vláknem ) může být složitý, neboť může výhodně dědit od nějaké bohaté třídy. PJV06

1. způsob: objekt Tik – je vláknem class Tik extends Thread { @Override // překrytí prázdné metody třídy Thread public void run( ) { 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. PJV06

2. způsob: objekt Tak – není vláknem class Tak extends Orloj implements Runnable { @Override // překrytí abstraktní metody interfejsu Runnable public void run( ) { try { while( true ) { System.out.println( " Tak " ); Thread.sleep( 1000 ); // static method } } 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( ); Objekt Tak není vláknem, ač má metodu run ( tu však nelze odstartovat ), - volá ji nepřekrytá metoda run Threadu, neb objekt Tak je jejím targetem. PJV06

CPU time priority queue Tik a Tak Tik is Thread Thread has Tak java.lang. Object java.util .concurrent java.lang. any. ForkJoin WorkThread Thread Orloj CPU time priority queue java.lang. run() { } static sleep() Tik Thread start() Runnable run() ; my. my. call return Tik Tak Tak run() {…} run() {…} class vlákno nevlákno interface extends implements PJV06

Interakce vláken Vlákna mohou běžet nezávisle, mohou se vzájemně hledat, testovat, [ne]koordinovaně ovlivňovat či mohou spolupracovat a to metodami pro: hledání: static: currentThread( ), activeCount( ), holdsLock(…) , … getThreadGroup( ), ... testování: static: interrupted( ) isAlive( ), isDaemon( ), isInterrupted( ), getState(), … ovlivnění: start( ), nastavení proměnných, interrupt( ), setPriority( … ), yield( ), setName( … ), ... Následují metody využívají služby synchronizačního monitoru: respekt: synchronized - klíčové slovo definuje kritickou sekci naváznost: join( … ) - na ukončenou činnost jiného vlákna spolupráci: wait( … ) - čekání na znovu přidělení zámku, notify( ) - nespecifické upozornění čekajícímu vláknu, notifyAll( ) resp. všem čekajícím vláknům PJV06

Virtuální interrupt vlákna pojednávají metody interrupt( ), isInterrupted( ) a static interrupted( ). Volání t . interrupt( ) provede akce podle stavu vlákna t : RUNNABLE / RUNNING : Jen nastaví vláknu t příznak přerušení. WAIT / join / sleeping : Vláknu t zruší příznak přerušení, změní mu stav na další tj. LOCK / RUNNABLE / RUNNING, což pak ve stavu RUNNING hned vyhodí InterruptedException. not alive : no op. IO blocked / Selector : jen pro nio channels – viz javadoc. Vlákno může přerušit samo sebe, pokud ho lze modifikovat, což ověří metoda checkAccess( ). Zamítnutí vede na SecurityException. Volání t . isInterrupted( ) nemění příznak přerušení, vrátí true je-li nastaven, jinak ( i pro not alive ) false. Volání Thread.interrupted( ) zruší příznak přerušení běžného vlákna, vrátí true byl-li předtím nastaven, jinak ( i pro not alive ) false. PJV06

Kritická sekce (1/2) je ta část programu v níž současná aktivita více vláken na témže objektu by mohla způsobit nekonzistenci dat. Nad tím bdí tzv. monitor coby klíčník. ( Obdobou je železniční autoblok, zpovědnice či uzamykatelná toaleta. ) Kritickou sekcí je metoda či blok označená modifikátorem synchronized . Vlákno do ní vstoupí získá-li zámek od určeného synchronizačního objektu a tím jiné vlákno nemůže do metody vstoupit a Objekt se však nezamyká ( má mít modifikátor private). Každý objekt ( i pole i class-objekt ) má právě jeden nesdílitelný zámek ( intrinsic či monitor lock ) Určení synchronizačního objekt, jehož zámek se užije: - pro instanční metody je to this objekt, - pro třídní metody je to popisný objekt třídy: Třída.class . - v bloku to explicitně určí programátor. Běžící vlákno, jež zámek nezíská, monitor přeřadí do stavu LOCK a to do lock-poolu synchronizačního objektu kde vyčká na přidělení onoho zámku. Kritické sekce lze i do sebe vkládat. Vlákno může tak získat i více zámků. PJV06

Kritická sekce (2/2) Když vlákno kritickou sekci opustí, monitor mu zámek odebere a přidělí ho nederministicky některému vláknu čekajímu v lock poolu a jeho stav změní na RUNNABLE. Vlákno jež je v kritické sekci, leč nemůže žádanou operaci zatím provést, zavolá metodu wait( [ timeout ] ) čímž mu monitor odebere zámek a přeřadí ho do stavu WAIT a to ve wait-poolu synchronizačního objektu, kde čeká na notifikaci, timeout či interupt po čemž je přeřazen do stavu LOCK a do v lock-poolu synchronizačního objektu. Tam vyčká na přidělení onoho zámku a přeřazení do stavu RUNNABLE. Teprve ve stavu RUNNING se vlákno vrátí z metody wait, leč znovu musí testovat zda už lze tu operaci vykonat, ne-li pak opět zavolá metodu wait. V kritické sekci může být tedy současně více vláken, ale jen jedno aktivní. Kritické sekce mají být co nejkratší - kvůli průchodnosti programu. PJV06

Synchronizace class X { ... synchronized ... method1 ( ... ) { /* Synchronizace na this objekt */ } … method2 ( ... ) { … // Nesynchronizovaná metoda synchronized( o1 ) { // Synchronizované bloky synchronized( o2 ) { // o1, o2 refererují nějaké objekty … // či this či Z.class či pole } … Atributy jejichž hodnoty se mění mají být private. Konstruktory a inicializátory provádí právě jedno vlákno a tedy synchronizace netřeba. PJV06

Osud state state state state state BLOCK completed interrupt( ) false isAlive( ) true BLOCK state completed interrupt( ) I/O end sleep(…) join(…) I/O start CPU scheduler start( ) run( ) {…} RUNNABLE state RUNNING state NEW DEAD interrupt( ) yield( ) interrupt( ) sets flag only sets flag only synchronized wait(…) acquires object’s lock must have lock then releases it notify( ) notifyAll( ) timeout interrupt( ) LOCK state WAIT state synchronization object’s lock pool synchronization object’s wait pool PJV06

Metoda final synchronized void join( … ) využívá vnitřně metodu final native void wait(…) ke známé fintě: já si tu počkám až ty (to) doděláš ( tj. trpělivě vyčkám jen určitý čas ) . Volání ty.join( [ timeout ] ); blokuje běžné vlákno ( já ), pokud je vlákno ty živé, nejdéle však po udanou dobu, je-li vlákno ty ještě neživé anebo již mrtvé, neblokuje se vlákno( já ) . Je-li běžné vlákno ( já ) netrpělivé, nedočká výsledku práce vlákna ty . Skutečný stav se musí zajistit programaticky. Čekající vlákno ( já ) může vytrhnout z čekání nějaké jiné vlákno ( ty / on ) metodou já.interrupt( ) jež vyhodí InterruptedException. Na ukončení vlákna může postupně čekat více vláken. Pro timeout == 0 je doba ∞ , tudíž join( ) je ekvivalentní join( 0 ). Vlákna se nijak vzájemně nenavazují ( tj. nesloučí se v nějaké jediné – neb každé samostatně doběhne ), navazují se jejich práce. PJV06

Story: pilný strýc a líný synovec Synovec lajdá ( je blokován ), než strýc dokončí své dílo ( vydělat miliony ) - čili až zemře. Žádný z nich si však mamonu dlouho neužije. Je-li synovec nedočkavý, zavolá join( timeout ) - získá jen část peněz. Spuštění : new Nephew( new Uncle( ) ); public class Nephew extends Thread { Uncle u; public Nephew( Uncle u ) { this.u=u; this.start( ); } public void run( ) { try { u.join( ); } catch( InterruptedException ex ) { } // 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 PJV06

Zmatek v hanebné bance public class PhonyBank { public static void main( String[ ] args ) { new Clerk( ).start( ); new Clerk( ).start( ); // tito dva pilní úředníci for ( int i=1; true; i++ ) System.out.println( i + ".:" + Accounts.dump( ) ) ; } class Accounts { static long a1=0 , a2 = 1000; // s dvěma účty zmatkují static void move( int x ) { a1 -= x; a2 += x; } // a škodí si navzájem 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 ) ); PJV06

Synchronizace v solidní bance FairBank zjedná nápravu tím, že transakce s účty dělají postupně: class Accounts { static private long a1 = 0, a2 = 1000; static synchronized void move( int x ) { a1 -= x; a2 += x; } // OK static synchronized String dump( ) { return a1+ “+" +a2+ “=" +( a1+a2 ); } } anebo takto: static void move( int x ) { synchronized ( Accounts.class ) { a1 -= x; a2 += x; } // OK Jak patrno v obou případech se (nevhodně) využívá zámek třídy Accounts. PJV06

PC-problém ( Producer – Consumer ) Bezpečný a poctivý sklad hmotných objektů je takovýto: Nelze se do něj vloupat ( proměnné musejí být private ). Žádný objekt se nesmí ztratit ani podstrčit. Tentýž objekt nelze odebrat dvakrát. Má dvě vyhrazené brány: PUT - pro producenty objektů, GET - pro konsumenty objektů. Petenti tj. producenti a konsumenti: - přicházejí v náhodných časech, - vzájemně se neznají a nekomunikují, - jen jeden petent může vstoupit dovnitř, pokud tam není žádný aktivní, - nevpuštění petenti čekají venku na další příležitost, - uvnitř čekající petenti jsou upozorňováni na změnu stavu skladu. Sklad má danou kapacitu a vykazuje krajní stavy: - plný - pak vpuštěný producent čeká, - prázdný - pak vpuštěný konsument čeká. * Provoz usměrňuje pan Monitor – takový komisní vrátný, který otvírá brány petentům, bere jim zámky a zavírá je do čekáren. PJV06

PC - problem put get Store Monitor lock Producers Consumers private synchronized put synchronized get Lock pool Wait pool PJV06

Monitor a metody wait a notify Monitor působí jako prostředník mezi čekajícími a notifikujícími vlákny, neboť ta se vůbec nestýkají. Monitor ovlivňují generální public final native void metody: wait ( ) - odebere vláknu zámek, zavede ho do čekárny Wait-pool wait( long timeout ) - totéž, časem uvolní vlákno do čekárny Lock-pool notify( ) - uvolní nějaké vlákno notifyAll( ) - uvolní všechna vlákna interrupt( ) - ( vznikne InterruptedException ) Volat je však může jen vlákno držící zámek, tj. jen uvnitř kritické sekce, jinak dojde k IllegalMonitorStateException. PJV06

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" ); } PJV06

Producer Consumer Problem class Box { // Box for one deposit only private Object x; public void print( String r ) { System.out.println( r+" Box has "+x ); } synchronized void put( Object z ) { // z must not be null while ( x!=null ) try { this.wait( ); } catch ( InterruptedException ex ) { } this.notifyAll( ); x = z; print( Thread.currentThread().toString() ); } synchronized Object get( ) { while ( x==null ) try { this.wait( ); } catch ( InterruptedException ex ) { } Object z = x; x = null; return z; PJV06

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 ) {…} } PJV06

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 ) { } } PJV06

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. PJV06

Proti uvíznutí Programátor znemožní uvíznutí takto: synchronized ( hammer ) { synchronized ( tongs ) { ... // work } Více nářadí lze vložit do kolekce synchronizované implicitně ( např. Vector ) anebo explicitně synchronizačním obalem ( např. ArrayList ) anebo do pole. Pole jsou synchronizované implicitně. private Collection tools = new Vector( ); tools.add( hammer ); tools.add( tongs ); tools.add(...); // fill tools synchronized ( tools ) { Object x = tools.get(...); PJV06

Strom vláken tvoří objekty třídy ThreadGroup, jenž 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 to 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 PJV06

Strom vláken aplikace system main main 5 MyThreadA 5 MyThreadB 5 Reference Handler 10 main 5 Finalizer 8 MyGroup MyThreadA 5 Signal Dispatcher 9 MyThreadB 5 Attach Listener 5 thread group daemon PJV06

Ukončení běhu vlákna Normální: metoda run objektu typu Thread skončí návratem do JVM. Vlákno je mrtvé tj. metoda isAlive( ) vrací false. Nelze ho oživit. Objekt je vyřazen z fronty na CPU čas i ze stromu vláken, jeho reference ke skupině je nastavena na null – je bezprizorný. 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é 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. PJV06

Č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 vyrovnáním skluzů. - 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. PJV06

Č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” ); } PJV06

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 a pak ho odstartuje. Toto vlákno prochází postupně statickými inicializátory. Leč tam 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( ) { // Thread[ main, 5, main] try { // call all static initializers // call T.main( args ) } catch ( Throwable ex ) { ex.printStackTrace( ); } // tiskne parte finally { /* release resources */ } } PJV06