Stav projektu OpenJDK

1. Prehľad

V tomto článku sa v krátkosti pozrieme na Project Loom. V podstate, primárnym cieľom Project Loom je podpora vysoko výkonného a ľahkého modelu súbežnosti v Jave.

2. Project Loom

Project Loom je pokus komunity OpenJDK zaviesť do Javy ľahký konštrukt súbežnosti. Prototypy Loom zatiaľ priniesli zmenu v JVM aj v knižnici Java.

Aj keď zatiaľ nie je k dispozícii žiadne plánované vydanie pre Loom, k posledným prototypom sa môžeme dostať na wiki projektu Loom.

Predtým, ako diskutujeme o rôznych konceptoch Loom, poďme diskutovať o súčasnom modeli súbežnosti v Jave.

3. Java model súbežnosti

V súčasnej dobe, Závit predstavuje základnú abstrakciu súbežnosti v Jave. Táto abstrakcia spolu s ďalšími súbežnými API uľahčuje písanie súbežných aplikácií.

Pretože však Java na implementáciu používa vlákna jadra OS, nedokáže splniť dnešnú požiadavku súbežnosti. Existujú najmä dva hlavné problémy:

  1. Nite sa nemôže zhodovať s mierkou súbežnej jednotky domény. Napríklad aplikácie zvyčajne umožňujú až milióny transakcií, používateľov alebo relácií. Počet vlákien podporovaných jadrom je však oveľa menší. Teda a Tvlákno pre každého používateľa nie je transakcia alebo relácia často uskutočniteľná.
  2. Väčšina súbežných aplikácií vyžaduje pre každú požiadavku určitú synchronizáciu medzi vláknami. Z tohto dôvodu medzi vláknami OS sa stane drahý kontextový prepínač.

Možným riešením takýchto problémov je použitie asynchrónnych súbežných API. Bežné príklady sú CompletableFuture a RxJava. Za predpokladu, že také API neblokujú vlákno jadra, dáva aplikácii jemnejšie zrnitú konštrukciu súbežnosti nad vláknami Java.

Na druhej strane, takéto API sa ladia ťažšie a integrujú sa do starších API. Existuje teda potreba ľahkého konštruktu súbežnosti, ktorý je nezávislý na vláknach jadra.

4. Úlohy a plánovače

Akákoľvek implementácia vlákna, ľahká alebo ťažká, závisí od dvoch konštrukcií:

  1. Úloha (známa tiež ako pokračovanie) - Postupnosť pokynov, ktoré sa môžu pozastaviť pre niektorú operáciu blokovania
  2. Plánovač - Na priradenie pokračovania k CPU a opätovné priradenie CPU z pozastaveného pokračovania

V súčasnej dobe, Java sa spolieha na implementácie OS pre pokračovanie aj pre plánovač.

Teraz, aby bolo možné prerušiť pokračovanie, je potrebné uložiť celý zásobník hovorov. A podobne, načítajte zásobník hovorov po obnovení. Pretože implementácia pokračovaní operačného systému obsahuje natívny zásobník volaní spolu so zásobníkom hovorov Java, vedie to k veľkej stope.

Väčším problémom je však použitie plánovača OS. Pretože plánovač pracuje v režime jadra, medzi vláknami nie je žiadny rozdiel. A s každou požiadavkou na procesor zaobchádza rovnako.

Tento typ plánovania je nie je optimálna najmä pre aplikácie Java.

Zvážte napríklad aplikačné vlákno, ktoré vykoná určitú akciu s požiadavkami a potom odovzdá údaje do iného vlákna na ďalšie spracovanie. Tu, bolo by lepšie naplánovať obidve tieto vlákna na rovnaký CPU. Ale keďže je plánovač agnostický voči vláknu požadujúcemu CPU, je nemožné to zaručiť.

Projekt Loom navrhuje vyriešiť tento problém prostredníctvom vlákna užívateľského režimu, ktoré sa spoliehajú na implementáciu runtime Java runtime namiesto implementácie OS.

5. Vlákna

V posledných prototypoch v OpenJDK bola pomenovaná nová trieda Vlákno sa zavádza do knižnice popri Závit trieda.

Keďže plánovaná knižnica pre Vlákna je podobný Závit, používateľská implementácia by tiež mala zostať podobná. Existujú však dva hlavné rozdiely:

  1. Vlákno by zabaliť ľubovoľnú úlohu do pokračovania interného používateľského režimu. To by umožnilo úlohe pozastaviť a pokračovať v runtime Java namiesto jadra
  2. Zasunutelný plánovač používateľského režimu (ForkJoinPool, napríklad)

Poďme si podrobne prejsť na tieto dve položky.

6. Pokračovanie

Pokračovanie (alebo spoločná rutina) je postupnosť pokynov, ktoré sa dajú získať a volajúci ich obnoví v neskoršej fáze.

Každé pokračovanie má vstupný bod a medzu klzu. Medza klzu je tam, kde bola pozastavená. Kedykoľvek volajúci pokračuje v pokračovaní, ovládací prvok sa vráti k poslednej medznej hodnote.

Je dôležité si to uvedomiť že toto pozastavenie / obnovenie sa teraz vyskytuje v jazykovom runtime namiesto OS. Preto zabraňuje nákladnému prepínaniu kontextu medzi vláknami jadra.

Projekt Loom sa podobne ako vlákna zameriava na podporu vnorených vlákien. Pretože vlákna sa vnútorne spoliehajú na pokračovania, musia podporovať aj vnorené pokračovania. Ak tomu chcete lepšie porozumieť, pouvažujte nad triedou Pokračovanie ktorý umožňuje hniezdenie:

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

Ako je uvedené vyššie, vnorené pokračovanie môže pozastaviť seba alebo ktorékoľvek z nasledujúcich pokračovaní odovzdaním premennej rozsahu. Pre tento dôvod, sú známe ako rozsahom pokračovania.

Pretože pozastavenie pokračovania by si tiež vyžadovalo uloženie zásobníka volaní, je tiež cieľom projektu Loom pridať ľahké obnovenie zásobníka pri obnovení pokračovania.

7. Plánovač

Predtým sme diskutovali o nedostatkoch plánovača OS pri plánovaní príbuzných vlákien na rovnakom CPU.

Aj keď je cieľom projektu Loom umožniť zapojiteľné plánovače s vláknami, ForkJoinPool v asynchrónnom režime sa použije ako predvolený plánovač.

ForkJoinPool pracuje na algoritmus kradnutia práce. Každé vlákno teda udržiava deque úlohy a vykonáva úlohu z jej hlavy. Navyše žiadne nečinné vlákno neblokuje, čaká na úlohu a namiesto toho ju stiahne z chvosta deque iného vlákna.

Jediný rozdiel v asynchrónnom režime je v tom pracovné vlákna ukradnú úlohu z hlavy iného deque.

ForkJoinPool pridá úlohu naplánovanú inou spustenou úlohou do miestneho frontu. Preto je vykonávanie na rovnakom CPU.

8. Záver

V tomto článku sme diskutovali o problémoch v súčasnom modeli súbežnosti Java a o zmenách navrhovaných v Project Loom.

Pritom sme tiež definovali úlohy a plánovače a pozreli sa na to, ako na to Fibers a ForkJoinPool by mohli poskytnúť alternatívu k Jave pomocou vlákien jadra.


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