Srautai. Gijų klasė ir „Runnable“ sąsaja. Klasės gija Mandagumo gija

  1. Kokie yra gijų prioritetai?

    Atsakymas į šį klausimą yra „JavaRush“ paskaitose.

    Norėdami optimizuoti „Java“ gijų lygiagretų veikimą, galima teikti prioritetą gijoms. Gijos, turinčios didesnį prioritetą, turi pranašumą, nes gauna procesoriaus laiką, palyginti su gijomis, kurių prioritetas mažesnis.

    Darbą su prioritetais teikia šie temų klasės metodai:

    public public void setPriority (int naujoPriority)

    Nustato sriegio prioritetą.

    viešas final int getPriority ()

    Leidžia žinoti gijos prioritetą.

    Parametro reikšmė naudojant „setPriority“ metodą negali būti savavališka. Jis turi būti nuo MIN_PRIORITY iki MAX_PRIORITY. Kai jis bus sukurtas, gija turi pirmenybę NORM_PRIORITY.

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

  2. Ar įmanoma sustabdyti siūlą sumažinus jo prioritetą iki 0?

    Straipsnio atsakymas: „50 geriausių klausimų interviu metu. Tema: daugiasluoksnė »

    Rasta forume.

    Yra šio straipsnio versija anglų kalba: 50 geriausių „Java“ temų interviu klausimų atsakymai gaivintojams, patyrusiems programuotojams

    „Java“ teikia turtingas API viskam, tačiau, keista, tačiau ji nepateikia patogių būdų, kaip sustabdyti giją. „JDK 1.0“ buvo keli kontrolės metodai, tokie kaip „stop“ (), sustabdyti () ir atnaujinti (), kurie buvo pažymėti kaip nebenaudojamas būsimose versijose dėl galimo aklavietės grėsmių, nuo to laiko „Java API“ kūrėjai nemėgino pateikti patikimo, saugaus ir elegantiško gijų sustabdymo būdo. Programuotojai dažniausiai remiasi tuo, kad gija sustoja pati, kai tik baigia vykdyti run () arba call () metodus. Norėdami sustabdyti rankiniu būdu, programuotojai pasinaudoja nepastoviu boolean kintamuoju ir patikrina jo vertę kiekvienoje iteracijoje, jei „run ()“ metode yra kilpų, arba pertraukite gijas su pertraukimo () metodu, kad staiga atšauktumėte užduotis.

    Konkrečiai šiuo klausimu: Aš niekada nemačiau, kad kas nors teiktų pirmenybę 0.

    Jei kas nors apie tai žino, rašykite komentaruose.

    Kodėl mums reikia „ThreadGroup“ klasės?

    „ThreadGroup“ yra gijų rinkinys, kuriame taip pat gali būti kitų gijų grupių. Gijų grupė sudaro medį, kuriame kiekviena gijų grupė turi tėvystę (išskyrus originalą). Gija turi teisę pasiekti duomenis iš savo gijų grupės, tačiau neturi tokios prieigos prie kitų grupių ar pagrindinės gijų grupės.

    Iš kurios gijų grupės susideda pagrindinis gija?

    Niekur neradau)) Pasakyk man, kur ji yra))

    Kas yra „ThreadPool“ modelis?

    Yra ištrauka iš vikipedijos straipsnio apie tai:

    Kompiuterių programavimo metu siūlų telkinio schema (taip pat pakartojami darbuotojai arba darbuotojo ir įgulos modelis) yra tokia, kai sukuriama daugybė gijų, kad būtų galima atlikti daugybę užduočių, kurios paprastai organizuojamos eilėje. Vykdomų užduočių rezultatai taip pat gali būti dedami į eilę, arba gali būti, kad užduotys neduos jokio rezultato (pavyzdžiui, jei užduotis skirta animacijai). Paprastai užduočių yra daug daugiau nei gijų. Kai tik gija baigs savo užduotį, ji pareikalaus iš eilės atlikti kitą užduotį, kol visos užduotys bus baigtos. Gija gali nutrūkti arba miegoti, kol bus naujų užduočių.

    Naudojamų gijų skaičius yra parametras, kurį galima suderinti, kad būtų užtikrintas geriausias našumas. Be to, siūlų skaičius gali būti dinamiškas, atsižvelgiant į laukiančių užduočių skaičių. Pvz., Žiniatinklio serveris gali pridėti gijų, jei pateikiama daugybė tinklalapio užklausų, ir gali pašalinti gijas, kai tos užklausos nusileidžia žemyn. Didesnio siūlų fondo kaina padidina išteklių naudojimą. Algoritmas, naudojamas nustatyti, kada kurti ar sunaikinti gijas, turės įtakos bendram našumui:

    • sukurkite per daug gijų, švaistomi ištekliai ir laikas, taip pat švaistomas nenaudojamų gijų kūrimas
    • sunaikinkite per daug gijų ir daugiau laiko praleisite vėliau, kurdami jas iš naujo
    • sukurdami temas per lėtai, klientas gali prastai veikti (ilgai laukti)

    Kompiuteriniame programavime yra siūlų telkinio modelis, kuriame sukuriamas tam tikras skaičius gijų, kad būtų galima atlikti daugybę užduočių, kurios paprastai yra išdėstytos eilėje. Atliktų užduočių rezultatai taip pat gali būti įrašyti į eilę, arba užduotys gali neduoti jokio rezultato (pavyzdžiui, jei užduotis skirta animacijai).

    Paprastai užduočių yra daug daugiau nei gijų. Kai gija baigs savo užduotį, ji pareikalaus iš eilės kitos užduoties, kol visos užduotys bus baigtos. Tada srautas gali būti nutrauktas arba užmigti. Naudojamų gijų skaičius yra parametras, kurį galima suderinti, kad būtų užtikrintas geriausias našumas. Be to, siūlų skaičius gali būti dinamiškas, atsižvelgiant į atsirandančių užduočių skaičių. Pvz., Žiniatinklio serveris gali pridėti srautus, jei pateikiamos užklausos dėl kelių tinklalapių, ir gali ištrinti srautus, kai yra mažiau užklausų. Didėjant siūlų fondo dydžiui, didėja kompiuterio išteklių naudojimas. Algoritmas, naudojamas nustatyti, kada kurti ar sunaikinti gijas, turės įtakos bendram našumui: - Per daug gijų reiškia eikvoti išteklius ir laiką.

    Sunaikinkite per daug gijų ir daugiau laiko praleisite vėliau, kad jas sukurtumėte - Sukūrus temas per lėtai, klientas gali būti prastesnis.

    Kodėl reikalinga „ThreadPoolExecutor“ klasė?

    viešosios klasės „ThreadPoolExecutor“ plėtoja „AbstractExecutorService“

    „ExecutorService“, kuri vykdo kiekvieną pateiktą užduotį, naudodama vieną iš kelių galimų telkimo gijų, paprastai sukonfigūruotą naudojant vykdytojų gamyklinius metodus.

    Gijų telkiniai išskiria dvi skirtingas problemas: paprastai jie pagerina našumą, atlikdami didelius asinchroninių užduočių kiekius, nes sumažėja skambučių pridėtinės išlaidos kiekvienai užduočiai, ir jie suteikia galimybę apriboti ir valdyti išteklius, įskaitant siūlus, naudojamus užduočių rinkiniui atlikti. Kiekvienas „ThreadPoolExecutor“ taip pat palaiko pagrindinę statistiką, pavyzdžiui, atliktų užduočių skaičių.

    Kad ši klasė būtų naudinga įvairiose situacijose, joje yra daug reguliuojamų parametrų ir išplečiamųjų svirtelių. Tačiau programuotojai yra įsitikinę, kad naudoja patogesnius „Executors“ gamyklos metodus „Executors.newCachedThreadPool () (neribotas gijų telkinys, su automatiniu gijų atkūrimu), Executors.newFixedThreadPool (int) (fiksuoto dydžio sriegių fondas) ir Executors.newSingleThreadExecutor () (vieno fono gija). kurie iš anksto sukonfigūruoja dažniausiai naudojamų atvejų parametrus.

    Ar žinote, kiek būdų sukurti giją?

    Kalbos lygiu yra du būdai, kaip sukurti giją. „Java.lang.Thread“ klasės objektas yra gija, tačiau jai vykdyti reikia užduoties, kuri yra objektas, įgyvendinantis „java.lang.Runnable“ sąsają. Kadangi „Thread“ klasė įgyvendina „Runnable“ sąsają, galite nepaisyti „run ()“ metodo paveldėdami savo klasę iš „Thread“ arba įdiegdami joje „Runnable“ sąsają.

    Kam naudojama „Ateities“ klasė?

    Ateitis kaupia asinchroninio skaičiavimo rezultatą. Galite pradėti skaičiavimą pateikdami kam nors Ateities objektą ir jį pamiršę. Objekto Ateitis savininkas rezultatą gali gauti, kai jis bus paruoštas.

    Kokie yra „Callable“ pranašumai prieš „Runnable“?

    Callable sąsaja yra kur kas labiau tinkama užduotims, skirtoms lygiagrečiam vykdymui, kurti nei „Runnable“ sąsaja arba „Thread“ klasė. Verta paminėti, kad galimybė pridėti tokią sąsają atsirado tik nuo „Java 5“, nes svarbiausia „Callable“ sąsajos savybė yra parametrizuotų tipų (generinių), kaip parodyta sąraše, naudojimas.

    Sąrašai Užduoties kūrimas naudojant „Callable 10 1“ importo „Java“ sąsają. util. vienu metu. Galima skambinti 11 2 viešosios klasės „CallableSample“ įgyvendina „Callable“ (12 3 viešų stygų kvietimas () meta išimtį (13 4, jei (kokia nors sąlyga)) (14 5 mesti naują „IOException“ ( "klaida apdorojant užduotį"); 15 6) 16 7 sistema. iš. println („užduotis apdorojama“); 17 8 grąžinti „rezultatą“; 18 9) 19 10)

    Nedelsiant reikia atkreipti dėmesį į 2 eilutę, kur nurodoma, kad Callable sąsaja yra parametrizuota, o jos konkretus įgyvendinimas - CallableSample klasė priklauso nuo stygos tipo. 3 eilutėje rodomas pagrindinio skambučio metodo parašas jau parametruotoje versijoje, nes eilutės tipas taip pat nurodomas kaip grįžimo tipas. Iš tikrųjų tai reiškia, kad buvo sukurta užduotis, kurios rezultatas bus „String“ tipo objektas (žr. 8 eilutę). Tokiu pat būdu galite sukurti užduotį, kurios metu bet kokio tipo objektas bus sukurtas ir grąžintas naudojant skambučio metodą. Toks sprendimas yra daug patogesnis, palyginti su vykdymo metodu „Runnable“ sąsajoje, kuris nieko neduoda (jo grąžinimo tipas negalioja), todėl norint išgauti užduoties rezultatą reikia sugalvoti apeiti būdus.

    Kitas „Callable“ sąsajos pranašumas yra galimybė „išmesti“ išimtis nepažeidžiant kitų vykdomų užduočių. 3 eilutė nurodo, kad išimties tipo išimtį galima „išmesti“ iš metodo, o tai iš tikrųjų reiškia bet kokią išimtį, nes visos išimtys yra java.lang.Exception palikuonys. 5 eilutėje ši funkcija naudojama kuriant patikrintą (patikrintą) IOException tipo išimtį. Paleidžiamos sąsajos vykdymo metodas visai neleido mesti kontroliuojamų išimčių, o nekontroliuojamos (vykdymo laiko) išimties metimas privertė sustoti giją ir visą programą.

    Ar įmanoma atšaukti užduotį, jei naudojatės „Ateities“ klase?

    Remiantis šia diskusija, iškelta ant stebulės, paaiškėja, kad neįmanoma.

    Ateitis turi „Future.cancel“ (boolean) metodą, kuris turėtų atšaukti užduoties vykdymą. Bet jei užduotis jau prasidėjo, paskambinę „Future.cancel“ (tiesa) jos tikrai nesustabdysite. „FutureTask“ diegimo versijose kodas vykdomas:

    if (mayInterruptIfRunning) (Sriegis r \u003d bėgikas; jei (r! \u003d nulis) r. pertraukimas ();)

    Tie. vėlgi, siūlai, kuriuose vykdoma užduotis, patariami tik sustabdyti vykdymą. Be to, mes net neturime galimybės išsiaiškinti, ar užduotis šiuo metu vykdoma, ar ne. Yra metodas „Future.isDone ()“, tačiau vėl jis grįžta tiesa ne tik tada, kai užduotis buvo baigta vykdyti, bet iškart po to, kai paskambinsite „Future.cancel“ (), net jei užduotis vis dar vykdoma (juk „Future.cancel“ (tiesa) nesustabdo jau pradėtos vykdyti užduoties).

    Na, jei mes patys parašysime visą kodą, tada galėsite kruopščiai apdoroti „Thread.isInterrupted ()“ tinkamose vietose ir viskas bus gerai. Bet jei mes vykdysime trečiosios šalies kodą? Ar turėtume išplėsti serverį su papildiniais? Kai kurie kreivai parašyti papildiniai gali lengvai sukelti neveikiančią viso serverio būseną, nes mes negalime teisingai nutraukti įšaldyto papildinio vykdymo.


Rusų terminijoje už termino Siūlas Sustiprintas vertimas „Srautas“. Nors šį žodį taip pat galima išversti kaip „gija“. Kartais užsienio mokymo medžiagoje srauto sąvoka yra tiksliai paaiškinta gijomis. Tęsiame loginę seriją - ten, kur yra siūlai, yra ir rutulys. O kur kamuolys, ten katė. Iš karto akivaizdu, kad vertėjai neturėjo kačių. Taigi kilo painiava. Be to, pagal šį terminą yra ir kitų gijų Srautas. Vertėjai paprastai yra keistai atrodantys žmonės.

Paleidus bet kurią programą, vadinama gija pagrindinis srautas (pagrindinis). Iš jo generuojami vaikų srautai. Pagrindinė gija paprastai yra paskutinė gija, kuria siekiama nutraukti programą.

Nepaisant to, kad pagrindinis sriegis sukuriamas automatiškai, jį galima valdyti per klasės objektą Siūlas. Norėdami tai padaryti, paskambinkite metodu currentThread (), po kurio galite kontroliuoti srautą.

Klasė Siūlas yra keletas srautų valdymo metodų.

  • getName () - gaukite srauto pavadinimą
  • „getPriority“ () gauti prioritetą gijai
  • gyvas () - nustatyti, ar siūlas teka
  • prisijungti () - laukti upelio pabaigos
  • bėgti () - pradėk srautą. Įrašykite joje savo kodą
  • miegoti () - pristabdyti srautą tam tikrą laiką
  • pradžia () - pradėti srautą

Gausime informaciją apie pagrindinę giją ir pakeisime jos pavadinimą.

Gija mainThread \u003d Thread.currentThread (); „mInfoTextView.setText“ („Dabartinė gija:“ + mainThread.getName ()); // Pakeiskite pavadinimą ir rodymą teksto lauke mainThread.setName („CatThread“); mInfoTextView.append ("\\ nNaujos gijos pavadinimas:" + mainThread.getName ());

Numatytasis pagrindinio gijos pavadinimas pagrindiniskurį mes pakeitėme Kateteris.

Gausime informacijos apie srauto pavadinimą, nenurodydami metodo.

Gija mainThread \u003d Thread.currentThread (); mInfoTextView.setText ("Dabartinė gija:" + mainThread);

Tokiu atveju galite pamatyti liniją Siūlas - srauto pavadinimas, jo prioritetas ir grupės pavadinimas.

Sukurkite savo srautą

Sukurti savo srautą nėra sunku. Pakanka paveldėti iš klasės Siūlas.

Mes deklaruojame vidinę klasę savo klasės viduje ir vadiname ją spustelėdami, vadindami metodą pradžia ().

Viešosios klasės „MyThread“ pratęsia temą (viešas negaliojimas vykdomas () (Log.d (TAG, „Mano gija veikia ...“);)) viešas negaliojimas onClick (rodinio vaizdas) (MyThread myThread \u003d new MyThread (); myThread.start ( );)

Arba galite perduoti metodo skambutį pradžia () statytojui.

„Public void onClick“ (Peržiūrėti rodinį) („MyThread myThread \u003d new MyThread ();) viešos klasės„ MyThread “pratęsia giją (// Constructor MyThread () (//) Sukurkite naują giją„ Super “(„ Antrasis gija “);„ Log.i “(TAG“) Sukuriamas antrasis srautas „+ tai“; start (); // Pradėti srautą) public void run () (Log.d (TAG, „Mano srautas veikia ...“); Pabandykite (už (int i \u003d 5; i\u003e 0; i--) (Log.i (TAG, „Antrasis siūlas:„ + i); Thread.sleep (500);)) pagauti („InterruptedException e“) (Log.i (TAG, „Antrasis siūlas nutrauktas“); )))

Vykdomos gijos sukūrimas

Yra sudėtingesnis srauto kūrimo variantas. Norėdami sukurti naują giją, turite įdiegti sąsają Paleidžiama. Srautą galite sukurti iš bet kurio objekto, įgyvendinančio sąsają. Paleidžiama ir paskelbti metodą bėgti ().

Vidinis metodas bėgti () jūs siunčiate naujos gijos kodą. Ši gija baigsis, kai metodas grįš.

Kai jūs paskelbiate naują klasę su sąsaja Paleidžiamareikia naudoti konstruktorių:

Gija (Vykdomas gijos_objektas, Styginių gijos_pavadinimas)

Pirmasis parametras nurodo klasės, įgyvendinančios sąsają, egzempliorių. Tai nustato, kur bus pradėtas gijos vykdymas. Antrasis parametras perduoda srauto pavadinimą.

Sukūrę naują giją, turite pradėti ją naudodami metodą pradžia (), kuris iš esmės sukelia metodo skambutį bėgti ().

Sukurkite naują giją mokymo projekte kaip įdėtą klasę ir paleiskite ją.

Paketas en.alexanderklimov.expresscourse; importuoti android.os.Bundle; importuoti „android.support.v7.app.AppCompatActivity“; importuoti android.util.Log; importuoti „android.view.View“; importuoti „android.widget.Button“; importuoti „android.widget.EditText“; importuoti „android.widget.TextView“; importuoti statinį ru.alexanderklimov.expresscourse.R.id.textViewInfo; viešosios klasės „MainActivity“ išplečia „AppCompatActivity“ (galutinė eilutės TAG \u003d „ExpressCourse“; privatus mygtukas „mButton“; privatus „EditText“ mResultEditText; privatus „TextView“ „mInfoTextView“; „@Override“ apsaugota negaliojanti „onCreate“ („Bundle savedInstanceState“) (super.onCreate. ); mButton \u003d (Mygtukas) findViewById (R.id.buttonGetResult); mResultEditText \u003d (EditText) findViewById (R.id.editText); mInfoTextView \u003d (TextView) findViewById (textViewidfo); „MyRunnable“); // sukurkite naują gijos bandymą (for (int i \u003d 5; i\u003e 0; i--)) („Log.i“ (TAG, „Pagrindinis gija:“ + i); „Thread.sleep“ (1000);) ) pagauti („InterruptedException e“) (Log.i (TAG, „Pagrindinis sriegis nutrauktas“);)) „MyRunnable“ padargai „Runnable“ (sriegio sriegis; // Constructor MyRunnable () (// Sukurti naują antrą sriegio sriegį \u003d naują giją (šį, "Sriegis, pavyzdžiui"); Log.i (TAG, "Antroji gija sukurta" + sriegis); thread.start (); // Vykdyti p otok) // Reikalingas „Runnable“ sąsajos viešojo tuštumos paleidimo () metodas (bandykite (už (int i \u003d 5; i\u003e 0; i--) („Log.i“ (TAG, „Antras siūlas:„ + i); „Thread.sleep" (500);)) pagauti („InterruptedException e“) („Log.i“ (TAG, „Antrasis siūlas nutrauktas“;))) )))

Viduje konstruktorius „MyRunnable“ () mes sukuriame naują klasės objektą Siūlas

Gija \u003d nauja gija (tai, pavyzdžiui, "Gija, pavyzdžiui");

Pirmasis parametras panaudojo objektą tai, o tai reiškia norą paskambinti metodu bėgti () šis objektas. Kitas metodas vadinamas. pradžia (), todėl pradedamas gijos vykdymas, pradedant nuo metodo bėgti (). Savo ruožtu metodas pradeda mūsų siūlų kilpą. Paskambinus metodui pradžia ()konstruktorius „MyRunnable“ () grąžina programos valdymą. Kai pagrindinis siūlas tęsia savo darbą, jis įeina į savo ciklą. Po to abu siūlai vykdomi lygiagrečiai.

Galite paleisti kelis, o ne tik antrą, ne tik pirmąjį, bet ir kitus. Tai gali sukelti problemų, kai dvi gijos bando dirbti tuo pačiu kintamuoju tuo pačiu metu.

Sinchronizuotas raktinis žodis - sinchronizuoti metodai

Norėdami išspręsti problemą su gijomis, kurios gali kelti painiavą, naudojama sinchronizacija.

Metodas gali turėti modifikatorių. sinchronizuotas. Kai gija yra sinchronizuoto metodo viduje, visi kiti gijos, bandantys skambinti tuo pačiu atveju, turėtų palaukti. Tai pašalina painiavą, kai kelios gijos bando panaudoti metodą.

Sinchronizuotas void meow (eilutės žinutė);

Be to, raktinis žodis sinchronizuotas gali būti naudojamas kaip operatorius. Galite uždaryti bloke sinchronizuotas metodo skambučiai kai kuriose klasėse:

Sinchronizuotas (objektas) (// sakiniai, kuriuos reikia sinchronizuoti)

Looperis

Srautas turi subjektus Looperis, Prižiūrėtojas, „MessageQueue“.

Kiekvienas siūlas turi vieną unikalų Looperis ir gali turėti daug Prižiūrėtojas.

Grafas Looperis pagalbinis srauto objektas, kuris jį valdo. Jis apdoroja gaunamus pranešimus, taip pat nurodo gijai nutraukti reikiamu metu.

Srautas gauna savo Looperis ir „MessageQueue“ per metodą „Looper.prepare“ () po paleidimo. „Looper.prepare“ () identifikuoja skambinančią giją, sukuria Looperis ir „MessageQueue“ ir suriša srautą su jais saugykloje Threadlocal. Metodas „Looper.loop“ () turėtų būti pašauktas bėgti Looperis. Jos darbą galite atlikti atlikdami metodą looper.quit ().

„Class LooperThread“ pratęsia giją („Public Handler mHandler“; „public void run“) („Looper.prepare (); mHandler \u003d new Handler“) („public void handleMessage“ („Message msg“) (// čia apdorokite gaunamus pranešimus); „Looper.loop“) ;))

Naudokite statinį metodą getMainLooper () prieiti Looperis pagrindinis siūlas:

„Looper mainLooper“ \u003d „Looper.getMainLooper“ ();

Sukurkite du siūlus. Mes pradėsime vieną pagrindiniame sraute, o antrą atskirai nuo pagrindinio. Mums užteks dviejų mygtukų ir etiketės.