Forskjellen mellom tråd og virtuell tråd i Java

1. Introduksjon

I denne opplæringen viser vi forskjellen mellom tradisjonelle tråder i Java og de virtuelle trådene introdusert i Project Loom.

Deretter vil vi dele flere bruksområder for virtuelle tråder og API-ene som prosjektet har introdusert.

Før vi begynner, må vi merke oss dette prosjektet er under aktiv utvikling. Vi kjører eksemplene våre på VM med tidlig tilgang: openjdk-15-loom + 4-55_windows-x64_bin.

Nyere versjoner av byggene er gratis å endre og bryte nåværende API-er. Når det er sagt, var det allerede en stor endring i API, som tidligere brukt java.lang.Fiber klasse er fjernet og erstattet med den nye java.lang.VirtualThread klasse.

2. Høynivåoversikt over tråd vs virtuell tråd

På høyt nivå, en tråd administreres og planlegges av operativsystemet, mens en virtuell tråd administreres og planlegges av en virtuell maskin. Nå, For å opprette en ny kjernetråd, må vi foreta et systemanrop, og det er en kostbar operasjon.

Derfor bruker vi trådbassenger i stedet for å omdisponere og distribuere tråder etter behov. Neste, hvis vi ønsker å skalere applikasjonen vår ved å legge til flere tråder på grunn av kontekstbytting og deres minnefotavtrykk, kan kostnadene ved å vedlikeholde disse trådene være betydelige og påvirke behandlingstiden.

Da vil vi vanligvis ikke blokkere disse trådene, og dette resulterer i bruk av ikke-blokkerende I / O-APIer og asynkrone APIer, noe som kan forstyrre koden vår.

Tvert imot, virtuelle tråder administreres av JVM. Derfor deres tildeling krever ikke systemanrop, og de er fri for operativsystemets kontekstbryter. Videre kjører virtuelle tråder på bærertråden, som er selve kjernetråden som brukes under panseret. Som et resultat, siden vi er fri for systemets kontekstbryter, kan vi gyte mange flere slike virtuelle tråder.

Deretter er en nøkkelegenskap for virtuelle tråder at de ikke blokkerer bæretråden vår. Med det blir blokkering av en virtuell tråd en mye billigere operasjon, ettersom JVM vil planlegge en annen virtuell tråd, slik at transportørtråden blir blokkert.

Til syvende og sist trenger vi ikke nå NIO eller Async APIer. Dette skal resultere i mer lesbar kode som er lettere å forstå og feilsøke. Likevel, fortsettelsen kan potensielt blokkere en bærertråd - spesifikt når en tråd kaller en innfødt metode og utfører blokkeringsoperasjoner derfra.

3. Ny Thread Builder API

I Loom fikk vi den nye byggherren API i Tråd klasse, sammen med flere fabrikkmetoder. La oss se hvordan vi kan lage standardfabrikker og virtuelle fabrikker og bruke dem for vår trådutførelse:

Kjørbar printThread = () -> System.out.println (Thread.currentThread ()); ThreadFactory virtualThreadFactory = Thread.builder (). Virtual (). Fabrikk (); ThreadFactory kernelThreadFactory = Thread.builder (). Fabrikk (); Tråd virtualThread = virtualThreadFactory.newThread (printThread); Tråd kernelThread = kernelThreadFactory.newThread (printThread); virtualThread.start (); kernelThread.start ();

Her er resultatet av ovennevnte kjøring:

Tråd [Tråd-0,5, hoved] VirtualThread [, ForkJoinPool-1-worker-3, CarrierThreads]

Her er den første oppføringen standarden toString utdata fra kjernetråden.

Nå ser vi i utgangen at den virtuelle tråden ikke har noe navn, og den kjøres på en arbeidertråd av Fork-Join-bassenget fra CarrierTråder trådgruppe.

Som vi kan se, uavhengig av den underliggende implementeringen, API er det samme, og det betyr at vi enkelt kan kjøre eksisterende kode på de virtuelle trådene.

Vi trenger heller ikke lære et nytt API for å gjøre bruk av dem.

4. Virtuell trådsammensetning

Det er en fortsettelse og en planlegger som sammen utgjør en virtuell tråd. Nå kan vår brukermodusplanlegger være en hvilken som helst implementering av Leder grensesnitt. Ovenstående eksempel har vist oss at vi som standard kjører på ForkJoinPool.

Nå, på samme måte som en kjernetråd - som kan kjøres på CPU-en, deretter parkeres, planlegges tilbake, og deretter gjenopptas kjøringen - en fortsettelse er en kjøringsenhet som kan startes, deretter parkeres (gir), planlegges tilbake og gjenopptas utførelsen på samme måte fra der den slapp og fortsatt administreres av en JVM i stedet for å stole på et operativsystem.

Vær oppmerksom på at fortsettelsen er et API på lavt nivå, og at programmerere bør bruke APIer på høyere nivå som bygger-API for å kjøre virtuelle tråder.

For å vise hvordan det fungerer under panseret, kjører vi imidlertid vår eksperimentelle fortsettelse:

var scope = new ContinuationScope ("C1"); var c = new Continuation (scope, () -> {System.out.println ("Start C1"); Continuation.yield (scope); System.out.println ("End C1");}); mens (! c.isDone ()) {System.out.println ("Start run ()"); c.run (); System.out.println ("End run ()"); }

Her er resultatet av ovennevnte kjøring:

Start run () Start C1 End run () Start run () End C1 End run ()

I dette eksemplet kjørte vi vår fortsettelse og bestemte oss på et tidspunkt for å stoppe behandlingen. Så når vi kjørte den på nytt, fortsatte vår fortsettelse fra der den slapp. Ved utgangen ser vi at løpe() metoden ble kalt to ganger, men fortsettelsen ble startet en gang og fortsatte deretter kjøringen på den andre løpeturen der den slapp.

Dette er hvordan blokkeringsoperasjoner er ment å bli behandlet av JVM. Når en blokkeringsoperasjon har skjedd, vil fortsettelsen gi seg, og bære tråden ulåst.

Så det som skjedde er at hovedtråden vår opprettet en ny stabelramme på samtalestakken for løpe() metode og fortsatte med utførelsen. Deretter, etter at fortsettelsen hadde gitt, lagret JVM den nåværende tilstanden for utførelsen.

Deretter har hovedtråden fortsatt kjøringen som om løpe() metoden returnerte og fortsatte med samtidig som Løkke. Etter den andre samtalen til fortsettelse løpe metode, JVM gjenopprettet tilstanden til hovedtråden til det punktet hvor fortsettelsen har gitt og fullført utførelsen.

5. Konklusjon

I denne artikkelen diskuterte vi forskjellen mellom kjernetråden og den virtuelle tråden. Deretter viste vi hvordan vi kunne bruke et nytt API for trådbygger fra Project Loom til å kjøre de virtuelle trådene.

Til slutt viste vi hva en fortsettelse er og hvordan den fungerer under panseret. Vi kan videre utforske tilstanden til Project Loom ved å inspisere VM for tidlig tilgang. Alternativt kan vi utforske flere av de allerede standardiserte Java-samtidighets-API-ene.


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