Programmering

Trådatferd i JVM

Gjenging refererer til praksis med å utføre programmeringsprosesser samtidig for å forbedre applikasjonsytelsen. Selv om det ikke er så vanlig å jobbe med tråder direkte i forretningsapplikasjoner, brukes de hele tiden i Java-rammer.

Som et eksempel, bruker rammer som behandler et stort informasjonsvolum, som Spring Batch, tråder for å administrere data. Manipulering av tråder eller CPU-prosesser forbedrer samtidig ytelsen, noe som resulterer i raskere og mer effektive programmer.

Få kildekoden

Få koden for denne Java Challenger. Du kan kjøre dine egne tester mens du følger eksemplene.

Finn din første tråd: Java viktigste () metode

Selv om du aldri har jobbet direkte med Java-tråder, har du jobbet indirekte med dem fordi Java's main () -metode inneholder en hovedtråd. Hver gang du har henrettet hoved() metode, har du også utført hoveddelen Tråd.

Studerer Tråd klasse er veldig nyttig for å forstå hvordan threading fungerer i Java-programmer. Vi får tilgang til tråden som utføres ved å påkalle currentThread (). getName () metode, som vist her:

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

Denne koden vil skrive ut "hoved", og identifisere tråden som for øyeblikket blir utført. Å vite hvordan du kan identifisere tråden som utføres, er det første trinnet for å absorbere trådkonsepter.

Livssyklusen til Java-tråden

Når du arbeider med tråder, er det viktig å være klar over trådtilstanden. Java-tråds livssyklus består av seks trådtilstander:

  • Ny: En ny Tråd() har blitt instantiert.
  • Kjørbar: The Tråds start() metoden er påkalt.
  • Løping: The start() metoden har blitt påkalt og tråden kjører.
  • Suspendert: Tråden er midlertidig suspendert, og kan gjenopptas av en annen tråd.
  • Blokkert: Tråden venter på en mulighet til å løpe. Dette skjer når en tråd allerede har påkalt synkronisert () metode og neste tråd må vente til den er ferdig.
  • Avsluttet: Gjennomføringen av tråden er fullført.
Rafael Chinelato Del Nero

Det er mer å utforske og forstå om trådtilstander, men informasjonen i figur 1 er nok til at du kan løse denne Java-utfordringen.

Samtidig behandling: Utvide en trådklasse

På den enkleste måten gjøres samtidig behandling ved å utvide en Tråd klasse, som vist nedenfor.

 offentlig klasse InheritingThread utvider tråd {InheritingThread (String threadName) {super (threadName); } public static void main (String ... inheriting) {System.out.println (Thread.currentThread (). getName () + "kjører"); ny InheritingThread ("inheritingThread"). start (); } @ Override public void run () {System.out.println (Thread.currentThread (). GetName () + "kjører"); }} 

Her kjører vi to tråder: Hovedtråd og ArvingTråd. Når vi påkaller start() metode med det nye inheritingThread (), logikken i løpe() metoden utføres.

Vi sender også navnet på den andre tråden i Tråd klassekonstruktør, så resultatet vil være:

 main kjører. inheritingThread kjører. 

Det kjørbare grensesnittet

I stedet for å bruke arv, kan du implementere Runnable-grensesnittet. Passering Kjørbar inne i en Tråd konstruktør resulterer i mindre kobling og mer fleksibilitet. Etter å ha passert Kjørbar, kan vi påberope oss start() metode akkurat som vi gjorde i forrige eksempel:

 offentlig klasse RunnableThread implementerer Runnable {public static void main (String ... runnableThread) {System.out.println (Thread.currentThread (). getName ()); ny tråd (ny RunnableThread ()). start (); } @ Override public void run () {System.out.println (Thread.currentThread (). GetName ()); }} 

Ikke-demon vs daemon-tråder

Når det gjelder utførelse, er det to typer tråder:

  • Ikke-demoniske tråder blir henrettet til slutten. Hovedtråden er et godt eksempel på en ikke-demon-tråd. Kode inn hoved() vil alltid bli utført til slutten, med mindre a System.exit () tvinger programmet til å fullføre.
  • EN daemon tråd er det motsatte, i utgangspunktet en prosess som ikke kreves utført til slutten.

Husk regelen: Hvis en omsluttende ikke-demon-tråd slutter før en demon-tråd, kjøres ikke daemon-tråden før slutten.

For å bedre forstå forholdet mellom tråder fra daemon og ikke-daemon, studer dette eksemplet:

 importere java.util.stream.IntStream; public class NonDaemonAndDaemonThread {public static void main (String ... nonDaemonAndDaemon) kaster InterruptedException {System.out.println ("Starter utførelsen i tråden" + Thread.currentThread (). getName ()); Thread daemonThread = new Thread (() -> IntStream.rangeClosed (1, 100000) .forEach (System.out :: println)); daemonThread.setDaemon (true); daemonThread.start (); Tråd. Søvn (10); System.out.println ("Slutt på utførelsen i tråden" + Thread.currentThread (). GetName ()); }} 

I dette eksemplet har jeg brukt en daemon-tråd for å erklære et område fra 1 til 100.000, gjenta dem alle og deretter skrive ut. Men husk at en daemontråd ikke vil fullføre utførelsen hvis ikke-demonens hovedtråd avsluttes først.

Utgangen vil fortsette som følger:

  1. Start av utførelse i hovedtråden.
  2. Skriv ut tall fra 1 til muligens 100.000.
  3. Avslutningen på kjøringen i hovedtråden, veldig sannsynlig før iterasjonen til 100.000 fullføres.

Den endelige produksjonen vil avhenge av JVM-implementeringen din.

Og det bringer meg til mitt neste punkt: tråder er uforutsigbare.

Trådprioritet og JVM

Det er mulig å prioritere trådutførelse med settPrioritet metoden, men hvordan den håndteres, avhenger av JVM-implementeringen. Linux, MacOS og Windows har alle forskjellige JVM-implementeringer, og hver vil håndtere trådprioritet i henhold til sine egne standarder.

Trådprioriteten du setter, påvirker imidlertid rekkefølgen på trådinnkallingen. De tre konstantene erklært i Tråd klasse er:

 / ** * Minimumprioritet som en tråd kan ha. * / offentlig statisk slutt int MIN_PRIORITY = 1; / ** * Standardprioriteten som er tildelt en tråd. * / public static final int NORM_PRIORITY = 5; / ** * Maksimal prioritet en tråd kan ha. * / offentlig statisk slutt int MAX_PRIORITY = 10; 

Prøv å kjøre noen tester på følgende kode for å se hvilken kjøringsprioritet du ender med:

 public class ThreadPriority {public static void main (String ... threadPriority) {Thread moeThread = new Thread (() -> System.out.println ("Moe")); Tråd barneyThread = ny tråd (() -> System.out.println ("Barney")); Tråd homerThread = ny tråd (() -> 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 (); }} 

Selv om vi setter moeTråd som MAX_PRIORITY, kan vi ikke stole på at denne tråden blir utført først. I stedet vil rekkefølgen på utførelsen være tilfeldig.

Konstanter vs enums

De Tråd klasse ble introdusert med Java 1.0. På den tiden ble prioriteringene satt med konstanter, ikke enums. Det er imidlertid et problem med å bruke konstanter: hvis vi passerer et prioritetstall som ikke er i området 1 til 10, setPriority () metoden vil kaste et IllegalArgumentException. I dag kan vi bruke enums for å komme oss rundt dette problemet. Å bruke enums gjør det umulig å føre et ulovlig argument, som både forenkler koden og gir oss mer kontroll over utførelsen.

Ta utfordringene med Java-tråder!

Du har lært litt om tråder, men det er nok for dette innleggets Java-utfordring.

For å starte, studer følgende kode:

 offentlig klasse ThreadChallenge {private static int wolverineAdrenaline = 10; public static void main (String ... doYourBest) {new Motorcycle ("Harley Davidson"). start (); Motorsykkel fastBike = ny motorsykkel ("Dodge Tomahawk"); fastBike.setPriority (Thread.MAX_PRIORITY); fastBike.setDaemon (falsk); fastBike.start (); Motorsykkel yamaha = ny motorsykkel ("Yamaha YZF"); yamaha.setPriority (Thread.MIN_PRIORITY); yamaha.start (); } statisk klasse Motorsykkel utvider tråd {Motorsykkel (String bikeName) {super (bikeName); } @ Override public void run () {wolverineAdrenaline ++; hvis (wolverineAdrenaline == 13) {System.out.println (this.getName ()); }}}} 

Hva blir resultatet av denne koden? Analyser koden og prøv å finne svaret selv, basert på det du har lært.

A. Harley Davidson

B. Dodge Tomahawk

C. Yamaha YZF

D. Ubestemt

Hva skjedde nå? Forstå tråder oppførsel

I koden ovenfor opprettet vi tre tråder. Den første tråden er Harley Davidson, og vi tildelte denne tråden standardprioriteten. Den andre tråden er Dodge Tomahawk, tildelt MAX_PRIORITY. Den tredje er Yamaha YZF, med MIN_PRIORITY. Så startet vi trådene.

For å bestemme rekkefølgen trådene skal kjøre i, kan du først merke deg at Motorsykkel klasse utvider Tråd klasse, og at vi har passert trådnavnet i konstruktøren. Vi har også overstyrt løpe() metode med en tilstand: hvis jerv Adrenalin er lik 13.

Selv om Yamaha YZF er den tredje tråden i vår rekkefølge for utførelse, og har MIN_PRIORITY, det er ingen garanti for at den vil bli utført sist for alle JVM-implementeringer.

Du kan også merke deg at i dette eksemplet setter vi Dodge Tomahawk tråd som daemon. Fordi det er en demonstråd, Dodge Tomahawk kan aldri fullføre henrettelsen. Men de andre to trådene er ikke-demon som standard, så Harley Davidson og Yamaha YZF tråder vil definitivt fullføre utførelsen.

For å avslutte, blir resultatet D: Ubestemt, fordi det ikke er noen garanti for at trådplanleggeren vil følge vår rekkefølge for utførelse eller trådprioritet.

Husk at vi ikke kan stole på programlogikk (rekkefølge av tråder eller trådprioritet) for å forutsi JVMs rekkefølge for utførelse.

Videoutfordring! Feilsøking av variable argumenter

Feilsøking er en av de enkleste måtene å fullt ut absorbere programmeringskonsepter samtidig som du forbedrer koden din. I denne videoen kan du følge med mens jeg feilsøker og forklarer utfordringen med trådadferd:

Vanlige feil med Java-tråder

  • Påkaller løpe() metode for å prøve å starte en ny tråd.
  • Prøver å starte en tråd to ganger (dette vil føre til en IllegalThreadStateException).
  • Å la flere prosesser endre tilstanden til et objekt når det ikke skal endres.
  • Skrive programlogikk som er avhengig av trådprioritet (du kan ikke forutsi den).
  • Å stole på rekkefølgen for trådutførelse - selv om vi starter en tråd først, er det ingen garanti for at den blir utført først.

Hva du skal huske på Java-tråder

  • Påkalle start() metode for å starte en Tråd.
  • Det er mulig å utvide Tråd klasse direkte for å kunne bruke tråder.
  • Det er mulig å implementere en trådhandling i en Kjørbar grensesnitt.
  • Trådprioritet avhenger av JVM-implementeringen.
  • Trådatferd vil alltid avhenge av JVM-implementeringen.
  • En daemon-tråd vil ikke fullføres hvis en vedlagte ikke-daemon-tråd slutter først.

Lær mer om Java-tråder på JavaWorld

  • Les Java 101-trådserien for å lære mer om tråder og kjører, trådsynkronisering, trådplanlegging med vent / varsling og tråddød.
  • Modern threading: En Java concurrency primer introduserer java.util.concurrent og svarer på vanlige spørsmål for utviklere som er nye for Java-samtidighet.
  • Moderne tråder for ikke helt nybegynnere gir mer avanserte tips og beste fremgangsmåter for å jobbe med java.util.concurrent.

Mer fra Rafael

  • Få flere raske kodetips: Les alle innleggene i Java Challengers-serien.
  • Bygg Java-ferdighetene dine: Besøk Java Dev Gym for en kodetrening.
  • Vil du jobbe med stressfrie prosjekter og skrive feilfri kode? Besøk NoBugsProject for din kopi av Ingen feil, ingen stress - Lag en livsendrende programvare uten å ødelegge livet ditt.

Denne historien, "Thread behavior in the JVM" ble opprinnelig utgitt av JavaWorld.

$config[zx-auto] not found$config[zx-overlay] not found