Java >> Java tutorial >  >> JDK

OpenJDK Project Loom

1. Oversigt

I denne artikel tager vi et hurtigt kig på Project Loom. I bund og grund er det primære mål med Project Loom at understøtte en letvægts samtidighedsmodel med høj gennemstrømning i Java.

2. Projektvæv

Project Loom er et forsøg fra OpenJDK-fællesskabet på at introducere en let samtidighedskonstruktion til Java. Prototyperne for Loom indtil videre har introduceret en ændring i JVM såvel som Java-biblioteket.

Selvom der ikke er nogen planlagt udgivelse til Loom endnu, kan vi få adgang til de seneste prototyper på Project Looms wiki.

Før vi diskuterer de forskellige begreber i Loom, lad os diskutere den nuværende samtidighedsmodel i Java.

3. Javas samtidighedsmodel

I øjeblikket Tråd repræsenterer kerneabstraktionen af ​​samtidighed i Java. Denne abstraktion sammen med andre samtidige API'er gør det nemt at skrive samtidige applikationer.

Men da Java bruger OS-kernetrådene til implementeringen, opfylder det ikke dagens krav om samtidighed. Der er især to store problemer:

  1. Tråde  kan ikke matche skalaen for domænets samtidighedsenhed. For eksempel tillader applikationer normalt op til millioner af transaktioner, brugere eller sessioner. Imidlertid er antallet af tråde, der understøttes af kernen, meget mindre. Således et T tråd for hver bruger, transaktion eller session er ofte ikke mulig.
  2. De fleste samtidige applikationer har brug for en vis synkronisering mellem tråde for hver anmodning. På grund af dette sker der et dyrt kontekstskift mellem OS-tråde.

En mulig løsning på sådanne problemer er brugen af ​​asynkrone samtidige API'er . Almindelige eksempler er CompletableFuture og RxJava. Forudsat at sådanne API'er ikke blokerer kernetråden, giver det en applikation en mere finkornet samtidighedskonstruktion oven på Java-tråde.

På den anden side er sådanne API'er sværere at fejlfinde og integrere med ældre API'er . Og derfor er der behov for en let samtidighedskonstruktion, som er uafhængig af kernetråde.

4. Opgaver og skemalæggere

Enhver implementering af en tråd, enten let eller tung, afhænger af to konstruktioner:

  1. Opgave (også kendt som en fortsættelse) – En sekvens af instruktioner, der kan suspendere sig selv for nogle blokeringsoperationer
  2. Scheduler – Til at tildele fortsættelsen til CPU'en og gentildele CPU'en fra en pauseret fortsættelse

I øjeblikket er Java afhængig af OS-implementeringer til både fortsættelsen og planlæggeren .

Nu, for at suspendere en fortsættelse, er det nødvendigt at gemme hele opkaldsstakken. Og på samme måde, hent opkaldsstakken ved genoptagelse. Da OS-implementeringen af ​​fortsættelser inkluderer den oprindelige opkaldsstak sammen med Javas opkaldsstak, resulterer det i et tungt fodaftryk .

Et større problem er dog brugen af ​​OS-planlægger. Da skemalæggeren kører i kernetilstand, er der ingen differentiering mellem tråde. Og den behandler hver CPU-anmodning på samme måde.

Denne type planlægning er ikke optimal for især Java-applikationer .

Overvej for eksempel en applikationstråd, som udfører en handling på anmodningerne og derefter videregiver dataene til en anden tråd til yderligere behandling. Her ville det være bedre at planlægge begge disse tråde på den samme CPU . Men da skemalæggeren er agnostisk over for den tråd, der anmoder om CPU'en, er dette umuligt at garantere.

Project Loom foreslår at løse dette gennem brugertilstandstråde, der er afhængige af Java-runtime-implementering af fortsættelser og planlæggere i stedet for OS-implementeringen .

5. Fibre

I de seneste prototyper i OpenJDK, en ny klasse ved navn Fiber introduceres til biblioteket ved siden af tråden klasse.

Siden det planlagte bibliotek for Fiber ligner Tråd , bør brugerimplementeringen også forblive ens. Der er dog to hovedforskelle:

  1. Fiber  ville pakke enhver opgave i en intern brugertilstand fortsættelse. Dette ville tillade opgaven at suspendere og genoptage i Java runtime i stedet for kernen
  2. En pluggbar brugertilstandsplanlægger (ForkJoinPool, for eksempel) ville blive brugt

Lad os gennemgå disse to punkter i detaljer.

6. Fortsættelse

En fortsættelse (eller co-rutine) er en sekvens af instruktioner, der kan give og blive genoptaget af den, der ringer på et senere tidspunkt.

Hver fortsættelse har et indgangspunkt og et vigepunkt. Flydegrænsen er, hvor den blev suspenderet. Hver gang den, der ringer, genoptager fortsættelsen, vender kontrollen tilbage til det sidste vigepunkt.

Det er vigtigt at indse at denne suspendering/genoptagelse nu sker i sprogets runtime i stedet for OS . Derfor forhindrer det det dyre kontekstskifte mellem kernetråde.

I lighed med tråde har Project Loom til formål at understøtte indlejrede fibre. Da fibre er afhængige af fortsættelser internt, skal de også understøtte indlejrede fortsættelser. For at forstå dette bedre, overvej et hold Fortsættelse  der tillader indlejring:

Continuation cont1 = new Continuation(() -> {
    Continuation cont2 = new Continuation(() -> {
        //do something
        suspend(SCOPE_CONT_2);
        suspend(SCOPE_CONT_1);
    });
});

Som vist ovenfor kan den indlejrede fortsættelse suspendere sig selv eller enhver af de omsluttende fortsættelser ved at sende en omfangsvariabel. Af denne grund er de kendt som omfang fortsættelser.

Da suspendering af en fortsættelse også vil kræve, at den gemmer opkaldsstakken, er det også et mål for projekt Loom at tilføje letvægtsstackhentning, mens fortsættelsen genoptages.

7. Planlægger

Tidligere diskuterede vi manglerne ved OS-planlæggeren med hensyn til at planlægge relaterbare tråde på den samme CPU.

Selvom det er et mål for Project Loom at tillade pluggbare planlæggere med fibre, ForkJoinPool i asynkron tilstand vil blive brugt som standardplanlægning.

ForkJoinPool  virker på arbejde-tyveri-algoritmen . Således opretholder hver tråd en opgavebeskrivelse og udfører opgaven fra hovedet. Ydermere blokerer enhver ledig tråd ikke, venter på opgaven og trækker den fra halen af ​​en anden tråds deque i stedet.

Den eneste forskel i asynkron tilstand er, at arbejdertrådene stjæler opgaven fra hovedet på en anden deque .

ForkJoinPool  føjer en opgave planlagt af en anden kørende opgave til den lokale kø. Derfor udføres det på den samme CPU.

8. Konklusion

I denne artikel diskuterede vi problemerne i Javas nuværende samtidighedsmodel og ændringerne foreslået af Project Loom.

I den forbindelse definerede vi også opgaver og planlæggere og så på, hvordan Fibres and ForkJoinPool kunne give et alternativ til Java ved hjælp af kerneltråde.


Java tag