Programmēšana

Vītnes uzvedība JVM

Vītne attiecas uz praksi vienlaicīgi izpildīt programmēšanas procesus, lai uzlabotu lietojumprogrammas veiktspēju. Lai gan tas nav tik izplatīts darbs ar pavedieniem tieši biznesa lietojumprogrammās, tos visu laiku izmanto Java ietvaros.

Piemēram, ietvari, kas apstrādā lielu informācijas apjomu, piemēram, Spring Batch, datu pārvaldībai izmanto pavedienus. Manipulējot ar pavedieniem vai CPU procesiem, vienlaikus tiek uzlabota veiktspēja, kā rezultātā tiek izveidotas ātrākas un efektīvākas programmas.

Iegūstiet pirmkodu

Iegūstiet šī Java Challenger kodu. Kamēr sekojat piemēriem, varat pats veikt testus.

Atrodiet savu pirmo pavedienu: Java galvenā () metode

Pat ja jūs nekad neesat strādājis tieši ar Java pavedieniem, jūs esat strādājis netieši ar tiem, jo ​​Java galvenā () metode satur galveno pavedienu. Jebkurā laikā, kad esat izpildījis galvenais () metodi, jūs esat izpildījis arī galveno Vītne.

Studēšana Vītne klase ir ļoti noderīga, lai saprastu, kā pavedieni darbojas Java programmās. Mēs varam piekļūt pavedienam, kas tiek izpildīts, izsaucot currentThread (). getName () metodi, kā parādīts šeit:

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

Šis kods drukās “main”, identificējot pavedienu, kas pašlaik tiek izpildīts. Zināšanas par to, kā identificēt izpildāmo pavedienu, ir pirmais solis, lai absorbētu pavedienu koncepcijas.

Java pavedienu dzīves cikls

Strādājot ar pavedieniem, ir ļoti svarīgi zināt pavedienu stāvokli. Java pavedienu dzīves cikls sastāv no sešiem pavedienu stāvokļiem:

  • Jauns: Jauns Vītne () ir instantiated.
  • Skrienams: Vītne's sākt() metode ir izmantota.
  • Skriešana: sākt() metode ir izsaukta un pavediens darbojas.
  • Apturēts: Pavediens ir īslaicīgi apturēts, un to var atsākt ar citu pavedienu.
  • Bloķēts: Pavediens gaida iespēju palaist. Tas notiek, kad viens pavediens jau ir izsaucis sinhronizēts () metodi un nākamajam pavedienam jāgaida, līdz tas ir pabeigts.
  • Likvidēts: Pavediena izpilde ir pabeigta.
Rafaels Šinelato Del Nero

Ir vairāk, ko izpētīt un saprast par pavedienu stāvokļiem, taču 1. attēlā norādītā informācija ir pietiekama, lai jūs varētu atrisināt šo Java izaicinājumu.

Vienlaicīga apstrāde: Thread klases paplašināšana

Vienkāršākā vienlaicīgā apstrāde tiek veikta, paplašinot a Vītne klasē, kā parādīts zemāk.

 publiskā klase InheritingThread paplašina Thread {InheritingThread (String threadName) {super (threadName); } public static void main (String ... mantošana) {System.out.println (Thread.currentThread (). getName () + "darbojas"); jauns InheritingThread ("mantojošais pavediens"). start (); } @Orride public void run () {System.out.println (Thread.currentThread (). GetName () + "darbojas"); }} 

Šeit mēs vadām divus pavedienus: MainThread un Mantojošais pavediens. Kad mēs izmantojam sākt() metodi ar jauno mantojot pavedienu (), loģika palaist () metode tiek izpildīta.

Mēs arī nododam otrā pavediena nosaukumu Vītne klases konstruktors, tāpēc izeja būs:

 galvenais darbojas. darbojas mantojumsThread. 

Runnable saskarne

Tā vietā, lai izmantotu mantojumu, jūs varētu ieviest Runnable saskarni. Iet garām Skrienams iekšpusē a Vītne konstruktora rezultāts ir mazāks savienojums un lielāka elastība. Pēc garāmejot Skrienams, mēs varam izmantot sākt() metodi tāpat kā mēs to darījām iepriekšējā piemērā:

 public class RunnableThread īsteno Runnable {public static void main (String ... runnableThread) {System.out.println (Thread.currentThread (). getName ()); new Thread (jauns RunnableThread ()). start (); } @Orride public void run () {System.out.println (Thread.currentThread (). GetName ()); }} 

Ne daemon vs daemon pavedieni

Izpildes ziņā ir divu veidu pavedieni:

  • Ne daemon pavedieni tiek izpildīti līdz beigām. Galvenais pavediens ir labs ne-daemon pavediena piemērs. Kods galvenais () vienmēr tiks izpildīts līdz beigām, ja vien a System.exit () liek programmu pabeigt.
  • A dēmonu pavediens ir pretējs, būtībā process, kuru nav nepieciešams izpildīt līdz beigām.

Atcerieties likumu: Ja aptverošais pavediens, kas nav dēmona pavediens, beidzas pirms dēmona pavediena, dēmona pavediens netiks izpildīts līdz beigām.

Lai labāk izprastu dēmonu un citu dēmonu pavedienu attiecības, izpētiet šo piemēru:

 importēt java.util.stream.IntStream; public class NonDaemonAndDaemonThread {public static void main (String ... nonDaemonAndDaemon) throws InterruptedException {System.out.println ("Izpildes sākšana pavedienā" + Thread.currentThread (). getName ()); Thread daemonThread = new Thread (() -> IntStream.rangeClosed (1, 100000) .forEach (System.out :: println)); daemonThread.setDaemon (true); daemonThread.start (); Vītne.miegs (10); System.out.println ("Izpildes beigas pavedienā" + Thread.currentThread (). GetName ()); }} 

Šajā piemērā es izmantoju dēmonu pavedienu, lai deklarētu diapazonu no 1 līdz 100 000, atkārtotu visus un pēc tam izdrukātu. Bet atcerieties, ka dēmona pavediens nepabeigs izpildi, ja dēmona galvenais pavediens tiks pabeigts vispirms.

Rezultāts notiks šādi:

  1. Izpildes sākums galvenajā pavedienā.
  2. Izdrukājiet numurus no 1 līdz, iespējams, 100 000.
  3. Izpildes beigas galvenajā pavedienā, ļoti iespējams, pirms ir pabeigta iterācija līdz 100 000.

Galīgais rezultāts būs atkarīgs no jūsu JVM ieviešanas.

Un tas mani noved pie mana nākamā punkta: pavedieni ir neparedzami.

Vītnes prioritāte un JVM

Ir iespējams piešķirt prioritāti pavedienu izpildei, izmantojot setPriority metodi, bet tas, kā tas tiek apstrādāts, ir atkarīgs no JVM ieviešanas. Linux, MacOS un Windows visiem ir dažādas JVM ieviešanas iespējas, un katra no tām rīkosies ar pavedienu prioritāti atbilstoši saviem noklusējumiem.

Jūsu iestatītā pavedienu prioritāte tomēr ietekmē pavedienu izsaukšanas kārtību. Trīs konstantes, kas deklarētas Vītne klases ir:

 / ** * Minimālā prioritāte, kāda var būt pavedienam. * / public static final int MIN_PRIORITY = 1; / ** * Noklusējuma prioritāte, kas tiek piešķirta pavedienam. * / public static final int NORM_PRIORITY = 5; / ** * Maksimālā prioritāte, kāda var būt pavedienam. * / publiskais statiskais gala int MAX_PRIORITY = 10; 

Mēģiniet izpildīt dažus testus ar šo kodu, lai uzzinātu, kāda izpildes prioritāte jums ir:

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

Pat ja mēs iestatītu moeThreadMAX_PRIORITY, mēs nevaram paļauties uz to, ka šis pavediens tiks izpildīts vispirms. Tā vietā izpildes secība būs nejauša.

Constants vs enums

The Vītne klase tika ieviesta ar Java 1.0. Tajā laikā prioritātes tika noteiktas, izmantojot konstantes, nevis uzskaites. Tomēr pastāv konstantu izmantošana: ja mēs nokārtojam prioritātes numuru, kas nav diapazonā no 1 līdz 10, setPriority () metode izmetīs IllegalArgumentException. Šodien mēs varam izmantot enums, lai apietu šo problēmu. Izmantojot enums, nav iespējams nodot nelikumīgu argumentu, kas gan vienkāršo kodu, gan dod mums lielāku kontroli pār tā izpildi.

Piedalieties Java pavedienu izaicinājumā!

Jūs esat uzzinājis tikai mazliet par pavedieniem, taču ar to pietiek šī ieraksta Java izaicinājumam.

Lai sāktu, izpētiet šo kodu:

 publiskā klase ThreadChallenge {private static int wolverineAdrenaline = 10; public static void main (String ... doYourBest) {jaunais motocikls ("Harley Davidson"). start (); Motocikls fastBike = jauns motocikls ("Dodge Tomahawk"); fastBike.setPriority (Thread.MAX_PRIORITY); fastBike.setDaemon (nepatiesa); fastBike.start (); Motocikls yamaha = jauns motocikls ("Yamaha YZF"); yamaha.setPriority (Thread.MIN_PRIORITY); yamaha.start (); } statiskā klase Motocikls pagarina pavedienu {Motocikls (String bikeName) {super (bikeName); } @Orride public void run () {wolverineAdrenaline ++; if (āmrijaAdrenalīns == 13) {System.out.println (this.getName ()); }}}} 

Kāda būs šī koda izeja? Analizējiet kodu un mēģiniet pats noteikt atbildi, pamatojoties uz iemācīto.

A. Hārlijs Deividsons

B. Dodge Tomahawk

C. Yamaha YZF

D. nenoteikts

Kas tikko notika? Izpratne par pavedienu uzvedību

Iepriekš minētajā kodā mēs izveidojām trīs pavedienus. Pirmais pavediens ir Hārlijs Deividsons, un mēs šim pavedienam piešķīrām noklusējuma prioritāti. Otrais pavediens ir Dodge Tomahawk, piešķirts MAX_PRIORITY. Trešais ir Yamaha YZF, ar MIN_PRIORITY. Tad mēs sākām pavedienus.

Lai noteiktu pavedienu izpildes secību, vispirms ņemiet vērā, ka Motocikls klase paplašina Vītne klasē, un ka mēs esam nodevuši pavediena nosaukumu konstruktorā. Mēs arī esam ignorējuši palaist () metode ar nosacījumu: ja āmrija adrenalīns ir vienāds ar 13.

Pat ja Yamaha YZF ir trešais pavediens mūsu izpildes kārtībā un ir MIN_PRIORITY, nav garantijas, ka tas tiks izpildīts pēdējais visiem JVM ieviešanas gadījumiem.

Varat arī atzīmēt, ka šajā piemērā mēs iestatījām Dodge Tomahawk pavediens kā dēmons. Tā kā tas ir dēmona pavediens, Dodge Tomahawk nekad nevar pabeigt izpildi. Bet pārējie divi pavedieni pēc noklusējuma nav dēmoni, tāpēc Hārlijs Deividsons un Yamaha YZF pavedieni noteikti pabeigs to izpildi.

Noslēgumā jāsaka, ka rezultāts būs D: nenoteikts, jo nav garantijas, ka pavedienu plānotājs ievēros mūsu izpildes kārtību vai pavedienu prioritāti.

Atcerieties, ka mēs nevaram paļauties uz programmas loģiku (pavedienu secību vai pavedienu prioritāti), lai prognozētu JVM izpildes kārtību.

Video izaicinājums! Mainīgo argumentu atkļūdošana

Atkļūdošana ir viens no vienkāršākajiem veidiem, kā pilnībā absorbēt programmēšanas koncepcijas, vienlaikus uzlabojot arī kodu. Šajā videoklipā varat sekot līdzi, kamēr es atkļūdoju un izskaidroju pavedienu uzvedības izaicinājumu:

Bieži pieļautās kļūdas ar Java pavedieniem

  • Aicinot palaist () metodi, lai mēģinātu sākt jaunu pavedienu.
  • Mēģinot sākt pavedienu divreiz (tas izraisīs IllegalThreadStateException).
  • Ļaujot vairākiem procesiem mainīt objekta stāvokli, kad tam nevajadzētu mainīties.
  • Rakstot programmas loģiku, kas balstās uz pavedienu prioritāti (to nevarat paredzēt).
  • Paļaujoties uz pavedienu izpildes kārtību - pat ja mēs vispirms sākam pavedienu, nav garantijas, ka tas tiks izpildīts pirmais.

Kas jāatceras par Java pavedieniem

  • Izsaukt sākt() metode, lai sāktu a Vītne.
  • Ir iespējams pagarināt Vītne klasē, lai izmantotu pavedienus.
  • A iekšpusē ir iespējams īstenot pavedienu darbību Skrienams interfeiss.
  • Vītnes prioritāte ir atkarīga no JVM ieviešanas.
  • Vītnes uzvedība vienmēr būs atkarīga no JVM ieviešanas.
  • Dēmona pavediens netiks pabeigts, ja vispirms beigsies aptverošais pavediens, kas nav daemona pavediens.

Uzziniet vairāk par Java pavedieniem JavaWorld

  • Izlasiet Java 101 pavedienu sēriju, lai uzzinātu vairāk par pavedieniem un palaistajiem materiāliem, pavedienu sinhronizāciju, pavedienu plānošanu ar gaidīšanu / paziņošanu un pavedienu nāvi.
  • Mūsdienu vītne: ievada Java vienlaicīguma grunti java.util.concurrent un atbild uz bieži uzdotajiem jautājumiem izstrādātājiem, kuri jauni ir Java vienlaikus.
  • Mūsdienu pavedieni ne visai iesācējiem piedāvā progresīvākus padomus un paraugpraksi darbam java.util.concurrent.

Vairāk no Rafaela

  • Iegūstiet vairāk ātru kodu padomu: izlasiet visus Java Challengers sērijas ierakstus.
  • Veidojiet savas Java prasmes: apmeklējiet Java Dev Gym, lai iegūtu koda treniņu.
  • Vai vēlaties strādāt pie projektiem bez stresa un uzrakstīt kodu bez kļūdām? Apmeklējiet savu kopiju vietnē NoBugsProject Bez kļūdām, bez stresa - izveidojiet programmatūru, kas maina dzīvi, neiznīcinot savu dzīvi.

Šo stāstu "Vītnes uzvedība JVM" sākotnēji publicēja JavaWorld.