Programavimas

Siūlų elgesys JVM

Siūlai nurodo programavimo procesų vykdymo vienu metu praktiką, siekiant pagerinti programos našumą. Nors nėra taip įprasta dirbti su gijomis tiesiogiai verslo programose, jos visada naudojamos „Java“ sistemose.

Pavyzdžiui, didelės apimties informaciją apdorojantys rėmai, pvz., „Spring Batch“, naudoja gijas duomenims tvarkyti. Vienu metu valdant gijas ar procesoriaus procesus pagerėja našumas, todėl gaunamos greitesnės ir efektyvesnės programos.

Gaukite šaltinio kodą

Gaukite šio „Java Challenger“ kodą. Jūs galite atlikti savo testus, kol laikysitės pavyzdžių.

Raskite savo pirmąją giją: „Java“ pagrindinis () metodas

Net jei niekada nedirbote tiesiogiai su „Java“ gijomis, dirbote netiesiogiai, nes „Java“ pagrindiniame () metode yra pagrindinė gija. Bet kada atliksite pagrindinis () metodas, jūs taip pat įvykdėte pagrindinį Siūlas.

Studijuojant Siūlas klasė yra labai naudinga norint suprasti, kaip „Java“ programose veikia siūlai. Mes galime pasiekti giją, kuri yra vykdoma iškviečiant currentThread (). getName () metodas, kaip parodyta čia:

 public class MainThread {public static void main (String ... mainThread) {System.out.println (Thread.currentThread (). getName ()); }} 

Šis kodas atspausdins „main“, identifikuodamas šiuo metu vykdomą giją. Žinojimas, kaip nustatyti vykdomą giją, yra pirmas žingsnis įsisavinant sriegio koncepcijas.

„Java“ gijos gyvavimo ciklas

Dirbant su gijomis, svarbu žinoti gijų būseną. „Java“ gijos gyvavimo ciklą sudaro šešios gijų būsenos:

  • Nauja: Naujas Gija () buvo išaiškinta.
  • Bėgama: Siūlas's pradžia () metodas.
  • Bėgimas: pradžia () metodas buvo naudojamas ir gija veikia.
  • Laikinai sustabdytas: Gija laikinai sustabdyta ir gali būti atnaujinta kita gija.
  • Užblokuota: Gija laukia progos bėgti. Tai atsitinka, kai viena gija jau iškvietė sinchronizuotas () metodas, o kita gija turi palaukti, kol ji bus baigta.
  • Nutraukta: Gijos vykdymas baigtas.
Rafaelis Chinelato Del Nero

Yra daugiau dalykų, kuriuos reikia ištirti ir suprasti apie gijų būsenas, tačiau 1 paveiksle pateiktos informacijos pakanka, kad galėtumėte išspręsti šį „Java“ iššūkį.

Kartu atliekamas apdorojimas: „Thread“ klasės pratęsimas

Paprasčiausias tuo pačiu metu atliekamas apdorojimas pratęsiant a Siūlas klasės, kaip parodyta žemiau.

 viešoji klasė „InheritingThread“ pratęsia siūlą {InheritingThread (String threadName) {super (threadName); } public static void main (String ... paveldimas) {System.out.println (Thread.currentThread (). getName () + "veikia"); nauja „InheritingThread“ („paveldėjimo gija“). start (); } @Paisyti viešojo tuštumo vykdymą () {System.out.println (Thread.currentThread (). GetName () + "veikia"); }} 

Čia mes vykdome dvi gijas: „MainThread“ ir Paveldima gija. Kai mes kreipiamės į pradžia () metodas su naujuoju paveldėti giją (), logika paleisti () metodas yra vykdomas.

Mes taip pat perduodame antrosios gijos pavadinimą Siūlas klasės konstruktorius, todėl išvestis bus:

 pagrindinis veikia. veikia paveldėjimasThread. 

„Runnable“ sąsaja

Užuot naudoję paveldėjimą, galite įdiegti „Runnable“ sąsają. Praeina Bėgama viduje a Siūlas konstruktorius lemia mažiau sukabinimo ir daugiau lankstumo. Pravažiavęs Bėgama, galime pasinaudoti pradžia () metodą, kaip mes darėme ankstesniame pavyzdyje:

 viešoji klasė „RunnableThread“ įgyvendina „Runnable“ {public static void main (String ... runnableThread) {System.out.println (Thread.currentThread (). getName ()); nauja gija (nauja RunnableThread ()). pradžia (); } @Paisyti viešą nieką run () {System.out.println (Thread.currentThread (). GetName ()); }} 

Ne daemon vs daemon temos

Kalbant apie vykdymą, yra dviejų tipų gijos:

  • Ne daemon gijos yra vykdomi iki pabaigos. Pagrindinė gija yra geras ne daemon gijos pavyzdys. Kodas pagrindinis () visada bus vykdoma iki pabaigos, nebent a System.exit () priverčia programą baigti.
  • A demono gija yra priešingai, iš esmės procesas, kurio nereikia vykdyti iki galo.

Prisiminkite taisyklę: Jei uždarasis ne „daemon“ siūlas baigiasi prieš „deemon“ giją, „deemon“ gija nebus vykdoma iki galo.

Norėdami geriau suprasti „daemon“ ir „ne daemon“ gijų santykį, išnagrinėkite šį pavyzdį:

 importuoti java.util.stream.IntStream; public class NonDaemonAndDaemonThread {public static void main (String ... nonDaemonAndDaemon) meta InterruptedException {System.out.println ("Vykdymo pradėjimas temoje" + Thread.currentThread (). getName ()); Thread daemonThread = new Thread (() -> IntStream.rangeClosed (1, 100000) .forEach (System.out :: println)); daemonThread.setDaemon (true); daemonThread.start (); Siūlai.miega (10); System.out.println ("Vykdymo pabaiga gijoje" + Thread.currentThread (). GetName ()); }} 

Šiame pavyzdyje aš naudoju „daemon“ giją, norėdamas deklaruoti diapazoną nuo 1 iki 100 000, pakartoti juos visus ir spausdinti. Tačiau atminkite, kad „daemon“ gija neužbaigs vykdymo, jei ne „daemon“ pagrindinis siūlas bus baigtas pirmiausia.

Rezultatas vyks taip:

  1. Vykdymo pradžia pagrindinėje gijoje.
  2. Spausdinkite skaičius nuo 1 iki 100 000.
  3. Vykdymo pabaiga pagrindinėje gijoje, labai tikėtina, kol baigsis iteracija iki 100 000.

Galutinis rezultatas priklausys nuo jūsų JVM įgyvendinimo.

Ir tai mane atveda prie kito klausimo: gijos nenuspėjamos.

Siūlų prioritetas ir JVM

Galima nustatyti prioritetą gijų vykdymui naudojant setPrioritetas metodas, bet kaip tai bus tvarkoma, priklauso nuo JVM įgyvendinimo. „Linux“, „MacOS“ ir „Windows“ turi skirtingus JVM diegimo variantus ir kiekvienas tvarkys gijos prioritetą pagal savo numatytuosius nustatymus.

Tačiau jūsų nustatytas temos prioritetas daro įtaką siūlų iškvietimo tvarkai. Trys konstantos, deklaruotos Siūlas klasės yra:

 / ** * Mažiausias prioritetas, kurį gali turėti gija. * / public static final int MIN_PRIORITY = 1; / ** * Numatytasis prioritetas, priskirtas gijai. * / public static final int NORM_PRIORITY = 5; / ** * Didžiausias prioritetas, kurį gali turėti gija. * / viešasis statinis galutinis int MAX_PRIORITY = 10; 

Pabandykite atlikti keletą bandymų naudodami šį kodą, kad sužinotumėte, koks vykdymo prioritetas jums galų gale:

 public class „ThreadPriority“ {public static void main (String ... threadPriority) {Thread moeThread = new Thread (() -> System.out.println ("Moe")); Gijos barneyThread = nauja gija (() -> System.out.println ("Barney")); Thread homerThread = new Thread (() -> System.out.println ("Homer")); moeThread.setPriority (siūlas.MAX_PRIORITY); barneyThread.setPriority (Thread.NORM_PRIORITY); homerThread.setPriority (Thread.MIN_PRIORITY); homerThread.start (); barneyThread.start (); moeThread.start (); }} 

Net jei ir nustatytume moeThread kaip MAX_PRIORITY, negalime tikėtis, kad ši gija bus įvykdyta pirmiausia. Vietoj to vykdymo tvarka bus atsitiktinė.

„Constants vs enums“

Siūlas klasė buvo pristatyta su „Java 1.0“. Tuo metu prioritetai buvo nustatomi naudojant konstantas, o ne išvada. Vis dėlto kyla problema naudojant konstantas: jei perduodame prioriteto numerį, kuris nėra diapazone nuo 1 iki 10, setPriority () metodas sukels „IllegalArgumentException“. Šiandien mes galime naudoti „enums“, kad apeitume šią problemą. Naudojant „enums“ neįmanoma perduoti neteisėto argumento, kuris supaprastina kodą ir suteikia mums daugiau galimybių kontroliuoti jo vykdymą.

Priimkite „Java“ gijų iššūkį!

Jūs tik šiek tiek sužinojote apie gijas, tačiau to pakanka šio įrašo „Java“ iššūkiui.

Norėdami pradėti, ištirkite šį kodą:

 viešoji klasė „ThreadChallenge“ {private static int wolverineAdrenaline = 10; public static void main (String ... doYourBest) {naujas motociklas ("Harley Davidson"). startas (); Motociklas „fastBike“ = naujas motociklas („Dodge Tomahawk“); „fastBike.setPriority“ („Thread.MAX_PRIORITY“); „fastBike.setDaemon“ (klaidinga); „fastBike.start“ (); Motociklas yamaha = naujas motociklas („Yamaha YZF“); yamaha.setPriority (siūlas.MIN_PRIORITY); yamaha.start (); } statinės klasės motociklas pratęsia siūlą {Motorcycle (String bikeName) {super (bikeName); } @ Nepaisyti viešo tuštumo bėgimo () {wolverineAdrenaline ++; if (wolverineAdrenaline == 13) {System.out.println (this.getName ()); }}}} 

Kokia bus šio kodo išvestis? Išanalizuokite kodą ir pabandykite patys nustatyti atsakymą, atsižvelgdami į tai, ko išmokote.

A. Harley Davidsonas

B. Dodge'as Tomahawkas

C. „Yamaha YZF“

D. Neapibrėžta

Kas ką tik nutiko? Suprasti gijų elgesį

Pirmiau pateiktame kode mes sukūrėme tris gijas. Pirmasis siūlas yra Harley Davidsonir šiai gijai priskyrėme numatytąjį prioritetą. Antroji gija yra Dodge Tomahawk, paskirta MAX_PRIORITY. Trečiasis yra „Yamaha YZF“, su MIN_PRIORITY. Tada pradėjome gijas.

Norėdami nustatyti temų vykdymo tvarką, pirmiausia turėtumėte atkreipti dėmesį, kad Motociklas klasė pratęsia Siūlas klasę ir kad mes perdavėme gijos pavadinimą konstruktoriuje. Mes taip pat nepaisėme paleisti () metodas su sąlyga: jei wolverineAdrenalinas yra lygus 13.

Nors ir „Yamaha YZF“ yra trečioji gija mūsų vykdymo tvarkoje ir turi MIN_PRIORITY, nėra jokios garantijos, kad jis bus vykdomas paskutinis visoms JVM diegimo programoms.

Taip pat galite pastebėti, kad šiame pavyzdyje mes nustatėme Dodge Tomahawk siūlas kaip deimonas. Kadangi tai yra „daemon“ gija, Dodge Tomahawk niekada negali užbaigti vykdymo. Tačiau kitos dvi gijos pagal numatytuosius nustatymus yra ne „daemon“, todėl Harley Davidson ir „Yamaha YZF“ gijos tikrai užbaigs jų vykdymą.

Apibendrinant, rezultatas bus D: Neapibrėžta, nes nėra jokios garantijos, kad gijų planuotojas laikysis mūsų vykdymo tvarkos ar gijų prioriteto.

Atminkite, kad negalime pasikliauti programos logika (gijų tvarka arba gijų prioritetu), kad numatytume JVM vykdymo tvarką.

Vaizdo iššūkis! Kintamųjų argumentų derinimas

Derinimas yra vienas iš paprasčiausių būdų visiškai įsisavinti programavimo koncepcijas, kartu tobulinant kodą. Šiame vaizdo įraše galite sekti, kol aš derinu ir paaiškinu gijų elgesio iššūkį:

Dažniausios „Java“ gijų klaidos

  • Kviečiant paleisti () metodas bandyti pradėti naują giją.
  • Bandote pradėti giją du kartus (tai sukels „IllegalThreadStateException“).
  • Leidimas keliems procesams pakeisti objekto būseną, kai jis neturėtų pasikeisti.
  • Rašyti programos logiką, kuri remiasi gijos prioritetu (jūs negalite to nuspėti).
  • Pasikliaudami gijų vykdymo tvarka - net jei mes pradėsime giją pirmiausia, nėra jokios garantijos, kad ji bus įvykdyta pirmiausia.

Ką atsiminti apie „Java“ gijas

  • Iškvieskite pradžia () metodas pradėti a Siūlas.
  • Galima pratęsti Siūlas klasės, kad būtų galima naudoti siūlus.
  • A viduje galima įgyvendinti gijų veiksmą Bėgama sąsaja.
  • Siūlų prioritetas priklauso nuo JVM įgyvendinimo.
  • Gijos elgesys visada priklausys nuo JVM įgyvendinimo.
  • „Daemon“ gija nebus baigta, jei pirmiausia baigsis gaubiamasis „ne daemon“ siūlas.

Sužinokite daugiau apie „Java“ gijas „JavaWorld“

  • Perskaitykite „Java 101“ gijų seriją, kad sužinotumėte daugiau apie gijas ir paleidžiamas programas, gijų sinchronizavimą, gijų planavimą laukiant / pranešant ir gijų mirtį.
  • Šiuolaikinis sriegimas: pristatomas „Java“ lygiagretumo pradmuo java.util.sąlyga ir atsako į dažniausiai užduodamus „Java“ lygiagretumo kūrėjams klausimus.
  • Šiuolaikiniai siūlai ne visai pradedantiesiems siūlo pažangesnius patarimus ir geriausią darbo praktiką java.util.sąlyga.

Daugiau iš Rafaelio

  • Gaukite daugiau greitų kodo patarimų: perskaitykite visus „Java Challengers“ serijos pranešimus.
  • Sukurkite savo „Java“ įgūdžius: apsilankykite „Java Dev“ sporto salėje ir atlikite kodo treniruotę.
  • Norite dirbti su projektais be streso ir parašyti kodą be klaidų? Norėdami rasti savo kopiją, apsilankykite „NoBugsProject“ Jokių klaidų, jokio streso - sukurkite gyvenimą keičiančią programinę įrangą, nesunaikindami savo gyvenimo.

Šią istoriją „Gijų elgesys JVM“ iš pradžių paskelbė „JavaWorld“.