Straumes. Vītņu klase un izpildāmais interfeiss. Klases pavediens Pieklājības pavediens

  1. Kādas ir pavedienu prioritātes?

    Atbilde uz šo jautājumu ir JavaRush lekcijās.

    Lai optimizētu Java pavedienu paralēlu darbību, ir iespējams prioritizēt pavedienus. Pavedieniem ar augstāku prioritāti ir priekšrocība iegūt procesora laiku salīdzinājumā ar pavedieniem ar zemāku prioritāti.

    Darbu ar prioritātēm nodrošina šādas pavedienu klases metodes:

    public final void setPriority (int newPriority)

    Iestata pavediena prioritāti.

    publiskā fināla int getPriority ()

    Ļauj uzzināt pavediena prioritāti.

    Parametra vērtība setPriority metodē nevar būt patvaļīga. Tam jābūt no MIN_PRIORITY līdz MAX_PRIORITY. Kad tas ir izveidots, pavedienam ir prioritāte NORM_PRIORITY.

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

  2. Vai ir iespējams apturēt pavedienu, pazeminot tā prioritāti līdz 0?

    Atbilde rakstā: “50 labākie jautājumi intervijā. Tēma: vairāku pavedienu izveidošana »

    Atrasts forumā.

    Ir šī raksta versija angļu valodā: Top 50 Java pavedienu intervijas jautājumu atbildes svaigajiem, pieredzējušajiem programmētājiem

    Java nodrošina bagātīgas API visam, taču, ironiski, tas nenodrošina ērtus pavedienu apturēšanas veidus. JDK 1.0 bija vairākas vadības metodes, piemēram, stop (), aptur () un resume (), kuras tika apzīmētas kā novecojis turpmākajos laidienos iespējamo strupceļa draudu dēļ kopš tā laika Java API izstrādātāji nav mēģinājuši nodrošināt stabilu, drošu un elegantu paņēmienu pavedienu apturēšanai. Programmētāji lielākoties paļaujas uz to, ka pavediens pats apstājas, tiklīdz tas pabeidz izpildes () vai izsaukuma () metodes. Lai apturētu manuāli, programmētāji izmanto nepastāvīgo Būla mainīgo un pārbauda tā vērtību katrā atkārtojumā, ja palaišanas () metodē ir cilpas, vai pārtrauciet pavedienus ar pārtraukt () metodi, lai pēkšņi atceltu darbus.

    Konkrēti par šo jautājumu: es nekad neesmu redzējis, ka kāds piešķir prioritāti 0.

    Ja kāds kaut ko par šo zina, tad raksti komentāros.

    Kāpēc mums ir nepieciešama ThreadGroup klase?

    ThreadGroup ir pavedienu kopums, kurā var būt arī citas pavedienu grupas. Diegu grupa veido koku, kurā katrai citai pavedienu grupai ir vecāks (izņemot oriģinālu). Vītnei ir tiesības piekļūt datiem no tās pavedienu grupas, bet tai nav šādas piekļuves citām grupām vai vecāku pavedienu grupai.

    No kuras pavedienu grupas sastāv galvenā pavediena grupa?

    Es nekur to neesmu atradis)) Sakiet, kur tas atrodas))

    Kas ir ThreadPool modelis?

    Par to ir izraksts no wikipedia raksta:

    Datorprogrammēšanā pavedienu kopas modelis (arī atkārtotie darbinieki vai strādnieku-apkalpes modelis) ir tāds, kurā tiek izveidoti vairāki pavedieni, lai veiktu vairākus uzdevumus, kas parasti tiek organizēti rindā. Izpildīto uzdevumu rezultātus var arī ievietot rindā, vai arī uzdevumi var nesniegt rezultātu (piemēram, ja uzdevums paredzēts animācijai). Parasti ir daudz vairāk uzdevumu nekā pavedieni. Tiklīdz pavediens būs pabeidzis savu uzdevumu, tas prasīs nākamo uzdevumu no rindas, līdz visi uzdevumi būs pabeigti. Pēc tam pavediens var tikt pārtraukts vai gulēt, līdz būs pieejami jauni uzdevumi.

    Izmantoto pavedienu skaits ir parametrs, kuru var noregulēt, lai nodrošinātu vislabāko sniegumu. Turklāt pavedienu skaits var būt dinamisks, pamatojoties uz gaidīšanas uzdevumu skaitu. Piemēram, tīmekļa serveris var pievienot pavedienus, ja ienāk daudz tīmekļa lapu pieprasījumu, un var noņemt pavedienus, kad šie pieprasījumi sašaurinās. Lielāka diegu kopuma izmaksas ir palielinātas resursu izmantošanas dēļ. Algoritms, ko izmanto, lai noteiktu, kad izveidot vai iznīcināt pavedienus, ietekmēs kopējo veiktspēju:

    • izveidojiet pārāk daudz pavedienu, un resursi tiek tērēti, un arī laiks tiek izšķiests, izveidojot neizmantotus pavedienus
    • iznīciniet pārāk daudz pavedienu, un vēlāk būs jāpavada vairāk laika, veidojot tos vēlreiz
    • pavedienu izveidošana pārāk lēni var izraisīt sliktu klienta veiktspēju (ilgi jāgaida)

    Datorprogrammēšanā ir pavedienu kopuma modelis, kurā tiek izveidots noteikts pavedienu skaits, lai veiktu vairākus uzdevumus, kas parasti tiek organizēti rindā. Pabeigto uzdevumu rezultātus var arī ievietot rindā, vai arī uzdevumi var nedot rezultātu (piemēram, ja uzdevums paredzēts animācijai).

    Parasti ir daudz vairāk uzdevumu nekā pavedieni. Kad pavediens būs pabeidzis uzdevumu, tas prasīs nākamo uzdevumu no rindas, līdz visi uzdevumi būs pabeigti. Pēc tam plūsma var tikt pārtraukta vai aizmigt. Izmantoto pavedienu skaits ir parametrs, kuru var noregulēt, lai nodrošinātu vislabāko sniegumu. Turklāt pavedienu skaits var būt dinamisks, pamatojoties uz radīto uzdevumu skaitu. Piemēram, tīmekļa serveris var pievienot straumes, ja pienāk pieprasījumi uz vairākām tīmekļa lapām, un var izdzēst straumes, ja ir mazāk pieprasījumu. Palielinoties pavedienu kopuma lielumam, palielinās arī datora resursu izmantošana. Algoritms, ko izmanto, lai noteiktu, kad izveidot vai iznīcināt pavedienus, ietekmēs kopējo veiktspēju: - Pārāk daudz pavedienu nozīmē resursu un laika tērēšanu.

    Iznīciniet pārāk daudz pavedienu, un vēlāk to izveidei tiks atvēlēts vairāk laika - pavedienu izveidošana pārāk lēni var pazemināt klienta veiktspēju.

    Kāpēc nepieciešama ThreadPoolExecutor klase?

    sabiedriskās klases ThreadPoolExecutor paplašina AbstractExecutorService

    ExecutorService, kas veic katru iesniegto uzdevumu, izmantojot vienu no vairākiem iespējamiem apvienošanas pavedieniem, kas parasti tiek konfigurēts, izmantojot izpildītāju rūpnīcas metodes.

    Vītņu kopas risina divas dažādas problēmas: tās parasti nodrošina uzlabotu sniegumu, veicot lielu daudzumu asinhrono uzdevumu, jo samazināts zvana piemaksa katram uzdevumam, un tie nodrošina līdzekļus ierobežot un pārvaldīt resursus, ieskaitot pavedienus, kas tiek izmantoti uzdevumu kopas izpildē. Katrs ThreadPoolExecutor atbalsta arī dažus statistikas pamatdatus, piemēram, pabeigto uzdevumu skaitu.

    Lai šī klase būtu noderīga plašā kontekstā, tā piedāvā daudzus pielāgojamus parametrus un paplašināšanas sviras. Tomēr programmētāji ir pārliecināti, ka izmanto ērtākas Executors rūpnīcas metodes Executors.newCachedThreadPool () (neierobežots pavedienu fonds, ar automātisku pavedienu atkopšanu), Executors.newFixedThreadPool (int) (fiksēta izmēra diegu fonds) un Executors.newSingleThreadExecutor () (viena fona pavediens). kas iepriekš konfigurē iestatījumus visbiežāk izmantotajiem gadījumiem.

    Cik veidus jūs zināt, kā izveidot pavedienu?

    Valodas līmenī ir divi veidi, kā izveidot pavedienu. Java.lang.Thread klases objekts ir pavediens, taču tam ir nepieciešams izpildes uzdevums, kas ir objekts, kas ievieš java.lang.Runnable saskarni. Tā kā Thread klasē tiek realizēts Runnable interfeiss, varat ignorēt run () metodi, pārmantojot savu klasi no Thread vai tajā ieviešot Runnable interfeisu.

    Kāpēc tiek izmantota Future klase?

    Nākotne saglabā asinhrona aprēķina rezultātu. Aprēķinu varat sākt, nodrošinot kādam kādu Nākotnes objektu un aizmirstot par to. Objekta Nākotne īpašnieks var iegūt rezultātu, kad tas ir gatavs.

    Kādas ir Callable priekšrocības salīdzinājumā ar Runnable?

    Callable interfeiss ir daudz piemērotāks paralēlu izpildei paredzētu uzdevumu radīšanai nekā Runnable interfeiss vai Thread klase. Ir vērts atzīmēt, ka spēja pievienot šādu saskarni parādījās tikai kopš Java 5, jo saskarnes Callable galvenā iezīme ir parametrētu tipu (sugas) lietošana, kā parādīts sarakstā.

    Sarakstā Uzdevuma izveidošana, izmantojot Callable 10 1 importa javas saskarni. util. vienlaicīga. Izsaucams 11 2 sabiedriskās klases CallableSample ievieš Callable (12 3 publisko virknes zvanu () met izņēmumu (13 4, ja (ir kāds nosacījums) (14 5 mest jauno IOException ( "kļūda uzdevuma apstrādes laikā"); 15 6) 16 7 sistēma. ārā. println ("uzdevums tiek apstrādāts"); 17 8 atgriešanās "rezultāts"; 18 9) 19 10)

    Nekavējoties jāpievērš uzmanība 2. rindiņai, kur tiek norādīts, ka Callable saskarne ir parametrizēta, un tās īpašā ieviešana - CallableSample klase ir atkarīga no virknes veida. 3. rinda parāda galvenās zvana metodes parakstu jau parametrētā versijā, jo virknes tips ir norādīts arī kā atgriešanās tips. Faktiski tas nozīmē, ka ir izveidots uzdevums, kura rezultāts būs String tipa objekts (sk. 8. rindu). Tādā pašā veidā jūs varat izveidot uzdevumu, kā rezultātā jebkura veida objekts tiks izveidots un atgriezts zvana veidā. Šāds risinājums ir daudz ērtāks, salīdzinot ar palaišanas metodi saskarnē Runnable, kas neko neatdod (tā atgriešanas tips nav derīgs), un tāpēc uzdevuma rezultāta iegūšanai ir jāizgudro risinājumi.

    Vēl viena saskarnes Callable priekšrocība ir spēja "izmest" izņēmumus, neietekmējot citus notiekošos uzdevumus. 3. rinda norāda, ka izņēmums no tipa izņēmuma var tikt “izmests” no metodes, kas faktiski nozīmē jebkuru izņēmumu, jo visi izņēmumi ir java.lang.Exception pēcnācēji. 5. rindā šo funkciju izmanto, lai izveidotu pārbaudītu (pārbaudītu) izņēmumu no tipa IOException. Palaižamās saskarnes palaišanas metode vispār neļāva mest kontrolētus izņēmumus, un nekontrolēta (izpildlaika) izņēmuma mešana lika pavedienam un visai lietojumprogrammai apstāties.

    Vai ir iespējams atcelt uzdevumu, ja izmantojat nākotnes klasi?

    Balstoties uz šo diskusiju, kas izvirzīta centrā, izrādās, ka tas nav iespējams.

    Future ir metode Future.cancel (Būla), kurai vajadzētu atcelt uzdevuma izpildi. Bet, ja uzdevums jau ir sācies, izsaucot Future.cancel (true), tas to patiešām neapturēs. FutureTask ieviešanas versijās kods tiek izpildīts:

    if (mayInterruptIfRunning) (Vītne r \u003d runner; if (r! \u003d null) r. pārtraukt ();)

    Tie. atkal pavediens, kurā darbojas uzdevums, ir ieteicams tikai pārtraukt izpildi. Turklāt mums pat nav iespējas noskaidrot, vai uzdevums šobrīd tiek veikts vai nē. Ir metode Future.isDone (), taču atkal tā atgriežas taisnība ne tikai tad, kad uzdevums pabeidza izpildi, bet tūlīt pēc izsaukšanas uz Future.cancel (), pat ja uzdevums joprojām darbojas (galu galā Future.cancel (taisnība) neaptur uzdevumu, kas jau sācis darboties).

    Ja mēs visu kodu uzrakstīsim paši, tad jūs varat rūpīgi apstrādāt Thread.isInterrupted () pareizajās vietās, un viss būs kārtībā. Bet ja mēs darbinām trešās puses kodu? Vai mums vajadzētu būt paplašināmam serverim ar spraudņiem? Jebkurš šķībi uzrakstīts spraudnis var viegli novest pie visa servera nedarbojas, jo mēs nevaram pareizi pārtraukt iesaldēta spraudņa izpildi.


Krievu terminoloģijā aiz termina Vītne Pastiprināts tulkojums “Straume”. Lai gan šo vārdu var tulkot arī kā “pavedienu”. Dažreiz ārvalstu mācību materiālos plūsmas jēdziens tiek precīzi izskaidrots pavedienos. Mēs turpinām loģisko sēriju - kur ir pavedieni, tur ir bumba. Un kur ir bumba, tur ir kaķis. Ir uzreiz skaidrs, ka tulkotājiem nebija kaķu. Tā radās apjukums. Turklāt šim terminam ir arī citi pavedieni Straume. Tulkotāji parasti ir dīvaini cilvēki.

Kad jebkura programma tiek startēta, tiek saukts pavediens galvenā straume (galvenais). No tā tiek ģenerētas bērnu straumes. Galvenais pavediens parasti ir pēdējais pavediens programmas pārtraukšanai.

Neskatoties uz to, ka galvenais pavediens tiek izveidots automātiski, to var vadīt, izmantojot klases objektu Vītne. Lai to izdarītu, piezvaniet uz metodi currentThread (), pēc kura jūs varat kontrolēt plūsmu.

Klase Vītne satur vairākas plūsmu pārvaldības metodes.

  • getName () - iegūstiet straumes vārdu
  • getPriority () iegūt pavediena prioritāti
  • ir dzīvs () - noteikt, vai pavediens darbojas
  • pievienoties () - pagaidiet straumes pabeigšanu
  • palaist () - sākt straumi. Ierakstiet tajā savu kodu
  • gulēt () - noteiktā laikā apturēt straumi
  • sākt () - sākt straumi

Mēs iegūsim informāciju par galveno pavedienu un mainīsim tā nosaukumu.

Pavediens mainThread \u003d Thread.currentThread (); mInfoTextView.setText ("Pašreizējais pavediens:" + mainThread.getName ()); // mainiet vārdu un displeju teksta laukā mainThread.setName ("CatThread"); mInfoTextView.append ("\\ nJauna pavediena nosaukums:" + mainThread.getName ());

Galvenā pavediena noklusējuma nosaukums galvenaiskuru mēs aizstājām ar Catthread.

Mēs iegūsim informāciju par straumes nosaukumu, nenorādot metodi.

Pavediens mainThread \u003d Thread.currentThread (); mInfoTextView.setText ("Pašreizējais pavediens:" + mainThread);

Šajā gadījumā jūs varat redzēt līniju Vītne - straumes nosaukums, tās prioritāte un grupas nosaukums.

Izveidojiet savu straumi

Izveidot savu straumi nav grūti. Pietiek ar mantošanu no klases Vītne.

Mēs deklarējam iekšējo klasi mūsu klases iekšienē un izsaucam to, noklikšķinot, izsaucot metodi sākt ().

Sabiedriskā klase MyThread paplašina pavedienu (public void run () (Log.d (TAG, "My thread are running ...");)) public void onClick (View view) (MyThread myThread \u003d new MyThread (); myThread.start ( );)

Alternatīvi, pārsūtiet metodes izsaukumu sākt () pie konstruktora.

Publisks voClick (skata skats) (MyThread myThread \u003d new MyThread ();) publiskās klases MyThread paplašina pavedienu (// Constructor MyThread () (//) Izveidot jaunu pavedienu super ("Otrais pavediens"); Log.i (TAG, " Tiek izveidota otrā straume "+ this); start (); // Start the stream) public void run () (Log.d (TAG," Mana straume darbojas ... "); try (for (int i \u003d 5; i\u003e 0; i--) (Log.i (TAG, "Otrais pavediens:" + i); Thread.sleep (500);)) nozveja (InterruptedException e) (Log.i (TAG, "Otrais pavediens pārtraukts"); )))

Palaišanas pavediena izveidošana

Straumes izveidošanai ir sarežģītāka iespēja. Lai izveidotu jaunu pavedienu, jums jāīsteno interfeiss Palaižams. Straumi var izveidot no jebkura objekta, kas ievieš saskarni. Palaižams un pasludina metodi palaist ().

Iekšējā metode palaist () jūs ievietojat koda jaunu pavedienu. Šis pavediens beigsies, kad metode atgriezīsies.

Kad jūs deklarējat jaunu klasi ar interfeisu Palaižamsjums jāizmanto konstruktors:

Vītne (izpildāms pavediena_objekts, stīgas pavediena nosaukums)

Pirmais parametrs norāda klases eksemplāru, kas ievieš saskarni. Tas nosaka, kur sāksies pavediena izpilde. Otrais parametrs nodod straumes nosaukumu.

Pēc jauna pavediena izveidošanas jums tas jāuzsāk, izmantojot metodi sākt (), kas būtībā izsauc metodes izsaukumu palaist ().

Mācību projektā kā ligzdotu klasi izveidojiet jaunu pavedienu un palaidiet to.

Komplekts en.alexanderklimov.expresscourse; importa android.os.Bundle; importēt android.support.v7.app.AppCompatActivity; importa android.util.Log; importa android.view.View; importēt android.widget.Button; importēt android.widget.EditText; importēt android.widget.TextView; importēt statisku ru.alexanderklimov.expresscourse.R.id.textViewInfo; publiskās klases MainActivity paplašina AppCompatActivity (galīgā virknes TAG \u003d "ExpressCourse"; privāta poga mButton; privāta EditText mResultEditText; privāta TextView mInfoTextView; @Override aizsargāta tukšums onCreate (Bundle savedInstanceState) (super.onCreate (savedInstanceState). ); mButton \u003d (Poga) findViewById (R.id.buttonGetResult); mResultEditText \u003d (EditText) findViewById (R.id.editText); mInfoTextView \u003d (TextView) findViewById (textViewidfo); MyRunnable (); // izveidojiet jaunu pavedienu mēģinājumu (for (int i \u003d 5; i\u003e 0; i--)) (Log.i (TAG, "Galvenā vītne:" + i); Thread.sleep (1000);) ) noķeršana (InterruptedException e) (Log.i (TAG, "Galvenā vītne pārtraukta");)) MyRunnable klases darbarīki Runnable (Threads thread; // Constructor MyRunnable () (// Izveidot jaunu otrā diega pavedienu \u003d new Thread (this, "Vītne, piemēram"); \u200b\u200bLog.i (TAG, "Otrais pavediens izveidots" + pavediens); thread.start (); // Palaist p otok) // Nepieciešamā metode Runnable interfeisa public void run () (mēģiniet (for (int i \u003d 5; i\u003e 0; i--) (Log.i (TAG, "Otrais pavediens:" + i); Thread.sleep (500);)) nozveja (InterruptedException e) (Log.i (TAG, "Otrais pavediens pārtraukts");)) )))

Iekšpusē konstruktors MyRunnable () mēs izveidojam jaunu klases objektu Vītne

Vītne \u003d jauns pavediens (tas, piemēram, "Vītne");

Pirmais parametrs izmantoja objektu šo, kas nozīmē vēlmi izsaukt metodi palaist () šis objekts. Tālāk tiek saukta metode. sākt (), kā rezultātā tiek sākta pavediena izpilde, sākot ar metodi palaist (). Savukārt metode sāk cilpu mūsu pavedienam. Pēc metodes izsaukšanas sākt ()konstruktors MyRunnable () atdod kontroli lietojumprogrammai. Kad galvenais pavediens turpina darbu, tas nonāk savā ciklā. Pēc tam abi pavedieni tiek izpildīti paralēli.

Papildus pirmajam varat palaist vairākus pavedienus, ne tikai otro pavedienu. Tas var radīt problēmas, ja divi pavedieni mēģina strādāt ar vienu un to pašu mainīgo vienlaikus.

Sinhronizēts atslēgas vārds - sinhronizētās metodes

Lai atrisinātu problēmu ar pavedieniem, kas var radīt neskaidrības, tiek izmantota sinhronizācija.

Metodei var būt modifikators. sinhronizēts. Kad pavediens atrodas sinhronizētā metodē, jāgaida visi citi pavedieni, kas to mēģina izsaukt vienā un tajā pašā gadījumā. Tas novērš neskaidrības, kad vairāki pavedieni mēģina izmantot metodi.

Sinhronizēts tukšs meow (stīgas ziņojums);

Turklāt atslēgvārds sinhronizēts var izmantot kā operatoru. Jūs varat ievietot blokā sinhronizēts dažu klašu metodes izsaukumi:

Sinhronizēts (objekts) (// paziņojumi, kuriem nepieciešama sinhronizācija)

Looper

Straumē ir entītijas Looper, Apstrādātājs, MessageQueue.

Katram pavedienam ir viens unikāls Looper un to var būt daudz Apstrādātājs.

Grāfs Looper papildu straumes objekts, kas to kontrolē. Tas apstrādā ienākošos ziņojumus un arī uzdod pavedienam pārtraukt pareizā laikā.

Straume kļūst tā Looper un MessageQueue izmantojot metodi Looper.prepare () pēc palaišanas. Looper.prepare () identificē izsaucēja pavedienu, izveido Looper un MessageQueue un saista straumi ar tiem krātuvē Threadlocal. Metode Looper.loop () jāaicina skriet Looper. Jūs varat pabeigt tā darbu, izmantojot metodi looper.quit ().

Klases LooperThread paplašina pavedienu (public Handler mHandler; public void run () (Looper.prepare (); mHandler \u003d new Handler () (public void handleMessage (Message msg) (// šeit apstrādā ienākošos ziņojumus)); Looper.loop () ;))

Izmantojiet statisko metodi getMainLooper () piekļūt Looper galvenais pavediens:

Looper mainLooper \u003d Looper.getMainLooper ();

Izveidojiet divus pavedienus. Mēs sāksim vienu galvenajā plūsmā, bet otro atsevišķi no galvenā. Mums pietiks ar divām pogām un etiķeti.