Forskellen mellem tråd og virtuel tråd i Java

1. Introduktion

I denne vejledning viser vi forskellen mellem traditionelle tråde i Java og de virtuelle tråde introduceret i Project Loom.

Derefter deler vi flere brugssager til virtuelle tråde og de API'er, som projektet har introduceret.

Før vi starter, skal vi bemærke det dette projekt er under aktiv udvikling. Vi kører vores eksempler på tidlig adgang væven VM: openjdk-15-væven + 4-55_windows-x64_bin.

Nyere versioner af builds er gratis at ændre og bryde aktuelle API'er. Når det er sagt, var der allerede en større ændring i API'en, som den tidligere anvendte java.lang.Fiber klasse er blevet fjernet og erstattet med den nye java.lang.VirtualThread klasse.

2. Højt niveau oversigt over tråd vs. virtuel tråd

På et højt niveau en tråd administreres og planlægges af operativsystemet, mens en virtuel tråd administreres og planlægges af en virtuel maskine. Nu, for at oprette en ny kernetråd skal vi foretage et systemopkald, og det er en dyr operation.

Derfor bruger vi trådpuljer i stedet for omfordeling og omfordeling af tråde efter behov. Dernæst, hvis vi vil skalere vores applikation ved at tilføje flere tråde på grund af kontekstskift og deres hukommelsesfodaftryk, kan omkostningerne ved vedligeholdelse af disse tråde være betydelige og påvirke behandlingstiden.

Derefter vil vi normalt ikke blokere disse tråde, og dette resulterer i anvendelser af ikke-blokerende I / O-API'er og asynkrone API'er, som kan rodde i vores kode.

Tværtimod, virtuelle tråde styres af JVM. Derfor er deres tildeling kræver ikke et systemopkald, og de er fri for operativsystemets kontekst switch. Desuden kører virtuelle tråde på bærertråden, som er den egentlige kernetråd, der bruges under hætten. Som et resultat, da vi er fri for systemets kontekstskift, kunne vi give mange flere sådanne virtuelle tråde.

Dernæst er en nøgleegenskab ved virtuelle tråde, at de ikke blokerer vores transportørtråd. Dermed bliver blokering af en virtuel tråd en meget billigere operation, da JVM planlægger en anden virtuel tråd og efterlader transportørtråden ikke blokeret.

I sidste ende behøver vi ikke nå ud til NIO eller Async API'er. Dette skulle resultere i en mere læselig kode, der er lettere at forstå og fejle. Alligevel, fortsættelsen kan potentielt blokere en transportørtråd - specifikt når en tråd kalder en oprindelig metode og udfører blokeringshandlinger derfra.

3. Ny Thread Builder API

I Loom fik vi den nye builder API i Tråd klasse sammen med flere fabriksmetoder. Lad os se, hvordan vi kan oprette standard- og virtuelle fabrikker og bruge dem til vores trådudførelse:

Kan køres printThread = () -> System.out.println (Thread.currentThread ()); ThreadFactory virtualThreadFactory = Thread.builder (). Virtuel (). Fabrik (); ThreadFactory kernelThreadFactory = Thread.builder (). Fabrik (); Tråd virtualThread = virtualThreadFactory.newThread (printThread); Tråd kernelThread = kernelThreadFactory.newThread (printThread); virtualThread.start (); kernelThread.start ();

Her er output fra ovenstående kørsel:

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

Her er den første post standard toString output af kernetråden.

Nu ser vi i output, at den virtuelle tråd ikke har noget navn, og den udføres på en arbejdertråd af Fork-Join-puljen fra CarrierTråde trådgruppe.

Som vi kan se, uanset den underliggende implementering, API'en er den samme, og det betyder, at vi let kunne køre eksisterende kode på de virtuelle tråde.

Vi behøver heller ikke lære en ny API for at gøre brug af dem.

4. Virtuel trådsammensætning

Det er en fortsættelse og en planlægning det udgør sammen en virtuel tråd. Nu kan vores bruger-mode planlægning være enhver implementering af Eksekutor interface. Ovenstående eksempel har vist os, at vi som standard kører på ForkJoinPool.

Nu, på samme måde som en kernetråd - som kan udføres på CPU'en, derefter parkeres, omplaneres tilbage og derefter genoptager dens udførelse - en fortsættelse er en eksekveringsenhed, der kan startes, derefter parkeres (afleveres), omplaneres tilbage og genoptages dens udførelse på samme måde fra hvor den slap og stadig styres af en JVM i stedet for at stole på et operativsystem.

Bemærk, at fortsættelsen er et API på lavt niveau, og at programmører skal bruge API'er på højere niveau som builder API til at køre virtuelle tråde.

Men for at vise, hvordan det fungerer under emhætten, kører vi nu vores eksperimentelle fortsættelse:

var scope = ny ContinuationScope ("C1"); var c = ny Fortsættelse (scope, () -> {System.out.println ("Start C1"); Continuation.yield (scope); System.out.println ("End C1");}); mens (! c.isDone ()) {System.out.println ("Start kørsel ()"); c.run (); System.out.println ("Afslut kørsel ()"); }

Her er output fra ovenstående kørsel:

Start kørsel () Start C1 Afslut kørsel () Start kørsel () Afslut C1 Afslut kørsel ()

I dette eksempel kørte vi vores fortsættelse og besluttede på et eller andet tidspunkt at stoppe behandlingen. Så når vi genkørte det, fortsatte vores fortsættelse fra det sted, hvor den slap. Ved output ser vi, at løb() metode blev kaldt to gange, men fortsættelsen blev startet en gang og fortsatte derefter sin udførelse på det andet løb, hvorfra den slap.

Sådan menes blokeringsoperationer at blive behandlet af JVM. Når en blokering sker, vil fortsættelsen give efter, så transporttråden ikke er blokeret.

Så hvad der skete er, at vores hovedtråd oprettede en ny stakramme på sin opkaldsstak til løb() metode og fortsatte med udførelsen. Derefter, efter at fortsættelsen havde givet, gemte JVM den aktuelle tilstand for udførelsen.

Dernæst har hovedtråden fortsat sin udførelse som om løb() metoden vendte tilbage og fortsatte med mens løkke. Efter det andet opkald til fortsættelse løb metode, JVM gendannede tilstanden for hovedtråden til det punkt, hvor fortsættelsen har givet og afsluttet udførelsen.

5. Konklusion

I denne artikel diskuterede vi forskellen mellem kernetråden og den virtuelle tråd. Dernæst viste vi, hvordan vi kunne bruge en ny trådbygger-API fra Project Loom til at køre de virtuelle tråde.

Endelig viste vi, hvad en fortsættelse er, og hvordan det fungerer under emhætten. Vi kan yderligere undersøge tilstanden af ​​Project Loom ved at inspicere den virtuelle adgangs-VM. Alternativt kan vi udforske flere af de allerede standardiserede Java-samtidige API'er.


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