Proudy. Třída vlákna a rozhraní Runnable. Závit třídy Zdvořilostní vlákno

  1. Jaké jsou priority vlákna?

    Odpověď na tuto otázku je v přednáškách JavaRush.

    Pro optimalizaci paralelního provozu vláken v Javě je možné upřednostňovat vlákna. Vlákna s vyšší prioritou mají výhodu v získávání času procesoru nad vlákny s nižší prioritou.

    Práce s prioritami jsou poskytovány následujícími metodami třídy vlákna:

    veřejná konečná neplatná sadaPriority (int newPriority)

    Nastavuje prioritu vlákna.

    veřejné finální int getPriority ()

    Umožňuje znát prioritu vlákna.

    Hodnota parametru v metodě setPriority nemůže být libovolná. Musí být mezi MIN_PRIORITY a MAX_PRIORITY. Když je vytvořeno, vlákno má přednost NORM_PRIORITY.

    MIN_PRIORITY \u003d 1.
    NORM_PRIORITY \u003d 5.
    MAX_PRIORITY \u003d 10.

  2. Je možné zastavit vlákno snížením jeho priority na 0?

    Odpověď v článku: „Top 50 otázek při rozhovoru. Téma: Vícevláknové »

    Nalezeno na fóru.

    V tomto článku je anglická verze: 50 nejčastějších dotazů na rozhovor s vlákny Java pro osvěžující, zkušené programátory

    Java poskytuje bohatá API pro všechno, ale paradoxně neposkytuje vhodné způsoby, jak zastavit vlákno. V JDK 1.0 bylo několik kontrolních metod, například stop (), suspend () a resume (), které byly označeny jako zastaralé v budoucích verzích kvůli potenciálním hrozbám zablokování, vývojáři Java API se od té doby nepokusili poskytnout robustní, bezpečný a elegantní způsob zastavení vláken. Programátoři většinou spoléhají na skutečnost, že se vlákno zastaví, jakmile dokončí provádění metod run () nebo call (). Pro ruční zastavení programátoři využívají těkavé booleovské proměnné a kontrolují její hodnotu při každé iteraci, pokud v metodě run () existují smyčky nebo přerušují vlákna pomocí metody přerušení () k náhlému zrušení úkolů.

    Konkrétně k problému: Nikdy jsem neviděl nikoho upřednostňovat na 0.

    Pokud o tom někdo ví, napište do komentářů.

    Proč potřebujeme třídu ThreadGroup?

    ThreadGroup je sada podprocesů, které mohou obsahovat i jiné skupiny podprocesů. Skupina vláken tvoří strom, ve kterém každá další skupina vláken má nadřazeného (kromě původního). Vlákno má právo přístupu k datům ze své skupiny vláken, ale nemá takový přístup k jiným skupinám nebo nadřazené skupině vláken.

    Z které skupiny vláken se skládá hlavní vlákno?

    Nikde jsem to nenašel)) Řekněte mi, kde to je))

    Co je to vzor ThreadPool?

    K dispozici je výňatek z článku wikipedia:

    V počítačovém programování je vzorec podprocesů (také replikovaní pracovníci nebo model pracovníka-posádky) tam, kde je vytvořeno množství podprocesů pro provádění řady úkolů, které jsou obvykle uspořádány ve frontě. Výsledky z prováděných úkolů mohou být také umístěny do fronty nebo úkoly nemusí vracet žádný výsledek (například pokud jde o animaci). Obvykle existuje mnohem více úkolů než vláken. Jakmile vlákno dokončí svůj úkol, vyžádá si další úlohu z fronty, dokud nebudou dokončeny všechny úkoly. Podproces pak může být ukončen nebo spán, dokud nebudou k dispozici nové úkoly.

    Počet použitých vláken je parametr, který lze vyladit tak, aby poskytoval nejlepší výkon. Počet vláken může být navíc dynamický na základě počtu čekajících úkolů. Webový server může například přidat vlákna, pokud přijde řada požadavků na webovou stránku, a může je odstranit, když se tyto požadavky zužují. Náklady na větší fond vláken jsou zvýšené využití zdrojů. Algoritmus použitý k určení, kdy vytvořit nebo zničit vlákna, bude mít dopad na celkový výkon:

    • vytvořit příliš mnoho podprocesů a zdroje jsou zbytečné a čas také zbytečný vytvářením nepoužitých podprocesů
    • zničit příliš mnoho vláken a více času bude stráveno později jejich vytvořením
    • příliš dlouhé vytváření vláken může vést ke špatnému výkonu klienta (dlouhé čekací doby)

    V počítačovém programování existuje model fondu podprocesů, ve kterém je vytvořen určitý počet podprocesů pro provádění řady úkolů, které jsou obvykle uspořádány ve frontě. Výsledky z dokončených úkolů lze také zařazovat do fronty nebo úkoly nemusí vracet žádný výsledek (například pokud jde o animaci).

    Zpravidla existuje mnohem více úkolů než vláken. Jakmile vlákno dokončí svou úlohu, vyžádá si další úlohu z fronty, dokud nebudou dokončeny všechny úkoly. Tok pak může být přerušen nebo usnout. Počet použitých vláken je parametr, který lze vyladit tak, aby poskytoval nejlepší výkon. Kromě toho může být počet vláken dynamický na základě počtu úkolů, které vyvstávají. Například webový server může přidat toky, pokud dorazí požadavky na více webových stránek, a může vymazat toky, když je méně požadavků. Jak se velikost fondu podprocesů zvětšuje, zvyšuje se využívání počítačových prostředků. Algoritmus použitý k určení, kdy vytvořit nebo zničit vlákna, bude mít vliv na celkový výkon: - Příliš mnoho vláken znamená plýtvání zdroji a časem.

    Zničte příliš mnoho podprocesů a více času strávíme později jejich vytvořením - příliš pomalé vytváření podprocesů může vést ke snížení výkonu klienta.

    Proč je potřeba třída ThreadPoolExecutor?

    veřejná třída ThreadPoolExecutor rozšiřuje službu AbstractExecutorService

    Služba ExecutorService, která provádí každou odeslanou úlohu pomocí jednoho z několika možných sdružovacích vláken, obvykle konfigurovaných pomocí továrních metod prováděcích programů.

    Fondy podprocesů řeší dva různé problémy: obvykle poskytují zlepšený výkon prováděním velkého množství asynchronních úkolů v důsledku snížené režie volání pro úlohu a poskytují prostředky pro omezení a správu zdrojů, včetně podprocesů použitých k dokončení sady úkolů. Každý ThreadPoolExecutor také podporuje některé základní statistiky, například počet dokončených úkolů.

    Aby byla tato třída užitečná v celé řadě souvislostí, poskytuje mnoho nastavitelných parametrů a páky rozšiřitelnosti. Programátoři jsou však přesvědčeni, že budou používat výhodnější tovární metody Executorů Executor.newCachedThreadPool () (neomezený fond podprocesů, s automatickým obnovením podprocesů), Executor.newFixedThreadPool (int) (fond podprocesů pevné velikosti) a Executor.newSingleThreadExecutor () (jediné pozadí podprocesu) které předkonfigurují nastavení pro nejběžnější případy použití.

    Kolik způsobů vytvoření vlákna znáte?

    Na jazykové úrovni existují dva způsoby, jak vytvořit vlákno. Objekt třídy java.lang.Thread je vlákno, ale potřebuje k provedení úkolu, což je objekt, který implementuje rozhraní java.lang.Runnable. Protože třída vlákna implementuje rozhraní Runnable, můžete přepsat metodu run () zděděním vaší třídy od vlákna nebo implementací rozhraní Runnable do ní.

    Na co se třída Future používá?

    Budoucnost ukládá výsledek asynchronního výpočtu. Výpočet můžete zahájit tak, že někomu poskytnete budoucí objekt a zapomenete na něj. Vlastník objektu Future může získat výsledek, až bude připraven.

    Jaké jsou výhody Callable oproti Runnable?

    Rozhraní Callable je mnohem vhodnější pro vytváření úkolů určených pro paralelní provádění než rozhraní Runnable nebo Thread. Je třeba poznamenat, že schopnost přidat takové rozhraní se objevila až od Java 5, protože klíčovou vlastností rozhraní Callable je použití parametrizovaných typů (generik), jak je uvedeno v seznamu.

    Výpis Vytvoření úlohy pomocí importovatelného java rozhraní Callable 10 1. util. souběžné. Volaný 11 2 veřejná třída CallableSample implementuje Callable (12 3 public String call () vyvolá výjimku (13 4 if (některé podmínky) (14 5 vyvolá novou IOException ( "chyba během zpracování úlohy"); 15 6) 16 7 Systém. ven. println ("úloha se zpracovává"); 17 8 návrat "výsledek"; 18 9) 19 10)

    Okamžitě je třeba věnovat pozornost řádku 2, kde je uvedeno, že rozhraní Callable je parametrizováno, a jeho konkrétní implementace - třída CallableSample, závisí na typu řetězce. Řádek 3 ukazuje podpis metody hlavního volání v již parametrizované verzi, protože typ řetězce je také určen jako typ návratu. Ve skutečnosti to znamená, že byla vytvořena úloha, jejímž výsledkem bude objekt typu String (viz řádek 8). Stejným způsobem můžete vytvořit úlohu, v jejímž důsledku bude objekt jakéhokoli požadovaného typu vytvořen a vrácen v metodě volání. Takové řešení je mnohem pohodlnější ve srovnání s metodou run v rozhraní Runnable, které nevrací nic (jeho návratový typ je neplatný), a proto je nutné vynalézt náhradní řešení, aby bylo možné extrahovat výsledek úkolu.

    Další výhodou rozhraní Callable je schopnost „vyvolávat“ výjimky bez ovlivnění probíhajících úkolů. Řádek 3 označuje, že výjimka typu Výjimka může být „vyhozena“ z metody, což ve skutečnosti znamená jakoukoli výjimku, protože všechny výjimky jsou potomci java.lang.Exception. Na řádku 5 se tato funkce používá k vytvoření kontrolované (zaškrtnuté) výjimky typu IOException. Metoda běhu runnable interface nedovolila házení řízených výjimek vůbec a házení nekontrolované (runtime) výjimky způsobilo zastavení podprocesu a celé aplikace.

    Je možné úlohu zrušit, pokud používáte třídu Future?

    Na základě této diskuse, zvednuté na náboji, se ukazuje, že to není možné.

    Future má metodu Future.cancel (boolean), která by měla zrušit provedení úkolu. Pokud ale úloha již začala, volání Future.cancel (true) ji opravdu nezastaví. V útrobách implementace FutureTask běží kód:

    if (mayInterruptIfRunning) (vlákno r \u003d runner; if (r! \u003d null) r. interrupt ();)

    Ty. Opět se podproces, ve kterém je úloha spuštěna, doporučuje pouze zastavit provádění. Navíc nemáme ani možnost zjistit, zda je úkol aktuálně prováděn nebo ne. Existuje metoda Future.isDone (), ale opět se vrací skutečný nejen po dokončení úlohy, ale ihned po volání Future.cancel (), i když je úloha stále spuštěna (Future.cancel (true) nakonec nezastaví úlohu, která již byla spuštěna).

    Pokud tedy sami napíšeme celý kód, můžete Thread.isInterrupted () na správných místech pečlivě zpracovat a vše bude v pořádku. Ale pokud spustíme kód třetí strany? Měli bychom mít rozšiřitelný server s pluginy? Jakýkoli zkreslený plugin může snadno vést k nefunkčnímu stavu celého serveru, protože nemůžeme správně přerušit provádění zmrazeného pluginu.


V ruské terminologii za tímto termínem Vlákno Posílený překlad „Stream“. Ačkoli toto slovo lze také přeložit jako „vlákno“. Někdy je v zahraničních vzdělávacích materiálech pojem toku vysvětlen přesně na vláknech. Pokračujeme v logické řadě - tam, kde jsou vlákna, je koule. A kde je míč, je tu kočka. Je zřejmé, že překladatelé neměli kočky. Tak vznikl zmatek. Pod tímto termínem jsou navíc další vlákna Proud. Překladatelé jsou obecně podivní lidé.

Při spuštění jakékoli aplikace se nazývá vlákno hlavní proud (hlavní). Z toho jsou generovány dětské toky. Hlavní vlákno je obvykle poslední vlákno, které program ukončí.

Přestože je hlavní vlákno vytvořeno automaticky, lze jej ovládat prostřednictvím objektu třídy Vlákno. Chcete-li to provést, volejte metodu currentThread (), po kterém můžete řídit tok.

Třída Vlákno obsahuje několik metod pro správu toků.

  • getName () - získejte název streamu
  • getPriority () - získat prioritu vlákna
  • je naživu () - určit, zda vlákno běží
  • připojit () - čekat na dokončení toku
  • run () - spusťte stream. Napište do něj kód
  • spánek () - pozastavit proud na daný čas
  • start () - zahájit proud

Získáme informace o hlavním vláknu a změníme jeho název.

Thread mainThread \u003d Thread.currentThread (); mInfoTextView.setText ("Aktuální vlákno:" + mainThread.getName ()); // Změnit název a zobrazit v textovém poli mainThread.setName ("CatThread"); mInfoTextView.append ("\\ nNové vlákno název:" + mainThread.getName ());

Výchozí název hlavního vlákna hlavníkteré jsme nahradili Catthread.

Budeme volat informace o názvu proudu bez zadání metody.

Thread mainThread \u003d Thread.currentThread (); mInfoTextView.setText ("Aktuální vlákno:" + mainThread);

V tomto případě můžete vidět řádek Vlákno - název proudu, jeho prioritu a název jeho skupiny.

Vytvořte si vlastní stream

Vytvoření vlastního proudu není obtížné. Stačí se zdědit od třídy Vlákno.

Vyhlašujeme vnitřní třídu uvnitř naší třídy a voláme ji kliknutím, voláním metody start ().

Veřejná třída MyThread rozšiřuje vlákno (public void run () (Log.d (TAG, "My thread is running ..."));)) public void onClick (Zobrazit pohled) (MyThread myThread \u003d new MyThread (); myThread.start ( );)

Nebo převeďte volání metody start () konstruktorovi.

Veřejné neplatné onClick (zobrazení pohledu) (MyThread myThread \u003d new MyThread ();) veřejná třída MyThread rozšiřuje vlákno (// Constructor MyThread () (// Vytvořit nový podproces super ("druhé vlákno"); Log.i (TAG, ") Druhý tok je vytvořen "+ toto"; start (); // Zahájení toku) public void run () (Log.d (TAG, "Můj stream běží ...")); zkuste (pro (int i \u003d 5; i\u003e) 0; i--) (Log.i (TAG, "Druhé vlákno:" + i); Thread.sleep (500);)) úlovek (InterrupttedException e) (Log.i (TAG, "Druhé vlákno přerušeno"); )))

Vytvoření spustitelného vlákna

Pro vytvoření streamu existuje složitější možnost. Chcete-li vytvořit nové vlákno, musíte implementovat rozhraní Runnable. Stream můžete vytvořit z libovolného objektu, který implementuje rozhraní. Runnable a deklarovat metodu run ().

Metoda uvnitř run () odesíláte kód pro nové vlákno. Toto vlákno skončí, jakmile se metoda vrátí.

Když deklarujete novou třídu s rozhraním Runnablemusíte použít konstruktor:

Vlákno (Runnable thread_object, String thread_name)

První parametr určuje instanci třídy, která implementuje rozhraní. Určuje, kde začne provádění podprocesu. Druhý parametr předává název proudu.

Po vytvoření nového vlákna je třeba jej spustit pomocí této metody start (), což v zásadě vyvolá volání metody run ().

Vytvořte nové vlákno uvnitř projektu školení jako vnořenou třídu a spusťte jej.

Balíček en.alexanderklimov.expresscourse; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import statického ru.alexanderklimov.expresscourse.R.id.textViewInfo; veřejná třída MainActivity rozšiřuje AppCompatActivity (final String TAG \u003d "ExpressCourse"; soukromé tlačítko mButton; soukromé EditText mResultEditText; soukromé TextView mInfoTextView; @Override chráněné void onCreate (Bundle uloženoInstanceState) (super.onCreate (uloženéInstanceState). ); mButton \u003d (Button) findViewById (R.id.buttonGetResult); mResultEditText \u003d (EditText) findViewById (R.id.editText); mInfoTextView \u003d (TextView) findViewById (textViewInfo);) veřejné neplatné onClick (zobrazení pohledu) MyRunnable (); // vytvořit nový pokus o vlákno (pro (int i \u003d 5; i\u003e 0; i--) (Log.i (TAG, "Hlavní vlákno:" + i); Thread.sleep (1000);)) ) catch (InterruptedException e) (Log.i (TAG, "Hlavní vlákno přerušeno");)) třída MyRunnable implementuje Runnable (vlákno podprocesu; // Konstruktor MyRunnable () (// Vytvoření nového druhého vlákna podprocesu \u003d nové vlákno (toto, "Příklad vlákna"); Log.i (TAG, "Vytvořeno druhé vlákno" + vlákno); vlákno.start (); // Spustit p otok) // Požadovaná metoda pro veřejné neplatné běhové rozhraní Runnable () (try (pro (int i \u003d 5; i\u003e 0; i--) (Log.i (TAG, "Druhé vlákno:" + i); Thread.sleep (500);)) úlovek (InterrupttedException e) (Log.i (TAG, "Druhé vlákno přerušeno");))) )))

Uvnitř konstruktoru MyRunnable () vytváříme nový objekt třídy Vlákno

Thread \u003d new Thread (this, "Thread například");

První parametr použil objekt tento, což znamená touha zavolat metodu run () tento objekt. Dále je metoda volána. start ()v důsledku toho začíná provádění podprocesu, počínaje metodou run (). Metoda zase začíná smyčku pro naše vlákno. Po vyvolání metody start ()konstruktér MyRunnable () vrátí ovládání aplikaci. Když hlavní vlákno pokračuje ve své práci, vstupuje do svého cyklu. Poté jsou obě vlákna spuštěna paralelně.

Kromě prvního vlákna můžete spouštět více vláken, nejen druhé vlákno. To může vést k problémům, když se dva vlákna pokusí pracovat se stejnou proměnnou současně.

Synchronizované klíčové slovo - synchronizované metody

K vyřešení problému s vlákny, které mohou být matoucí, se používá synchronizace.

Metoda může mít modifikátor. synchronizované. Pokud je vlákno uvnitř synchronizované metody, měly by počkat všechny ostatní vlákna, které se jej pokusí volat ve stejné instanci. To eliminuje zmatek, když se více vláken pokusí vyvolat metodu.

Syncronized void meow (String msg);

Kromě toho klíčové slovo synchronizované lze použít jako operátor. Můžete uzavřít do bloku synchronizované volání metody některé třídy:

Syncronized (object) (// příkazy vyžadující synchronizaci)

Looper

Stream má entity Looper, Psovod, MessageQueue.

Každé vlákno má jeden jedinečný Looper a může mít hodně Psovod.

Počet Looper objekt pomocného proudu, který jej řídí. Zpracovává příchozí zprávy a také dává pokyn podprocesu k ukončení ve správný čas.

Stream dostane svůj Looper a MessageQueue prostřednictvím metody Looper.prepare () po spuštění. Looper.prepare () identifikuje volající vlákno, vytvoří Looper a MessageQueue a sváže je k nim v úložišti Threadlocal. Metoda Looper.loop () by měl být povolán ke spuštění Looper. Tuto metodu můžete dokončit pomocí této metody looper.quit ().

Třída LooperThread rozšiřuje vlákno (public Handler mHandler; public void run () (Looper.prepare (); mHandler \u003d new Handler () (public void handleMessage (Message msg) (// zde zpracovává příchozí zprávy)); Looper.loop () ;))

Použijte statickou metodu getMainLooper () mít přístup Looper hlavní vlákno:

Looper mainLooper \u003d Looper.getMainLooper ();

Vytvořte dvě vlákna. Začneme jeden v hlavním toku a druhý odděleně od hlavního. Stačí nám dvě tlačítka a štítek.