Különbség a szál és a virtuális szál között a Java-ban

1. Bemutatkozás

Ebben az oktatóanyagban megmutatjuk a különbséget a Java hagyományos szálai és a Project Loomban bevezetett virtuális szálak között.

Ezután megosztjuk a virtuális szálak és a projekt által bevezetett API-k több használati esetét.

Mielőtt nekilátnánk, meg kell jegyeznünk ez a projekt aktív fejlesztés alatt áll. Példáinkat a VM korai hozzáférésű szövőszékeken fogjuk futtatni: openjdk-15-loom + 4-55_windows-x64_bin.

A buildek újabb verziói szabadon módosíthatják és megszakíthatják a jelenlegi API-kat. Ennek ellenére már korábban is jelentős változás történt az API-ban java.lang.Rost osztály eltávolításra került és lecserélték az újra java.lang.VirtualThread osztály.

2. Magas szintű áttekintés a szálról a virtuális szálról

Magas szinten, egy szálat az operációs rendszer irányít és ütemez, míg a virtuális szálakat egy virtuális gép kezeli és ütemezi. Most, egy új kernlánc létrehozásához rendszerhívást kell végrehajtanunk, és ez költséges művelet.

Ezért használunk szálkészleteket ahelyett, hogy szükség szerint átcsoportosítanánk és szálakat osztanánk. Ezután, ha további szálak hozzáadásával szeretnénk méretezni alkalmazásunkat, a kontextusváltás és memóriaterületük miatt a szálak fenntartásának költsége jelentős lehet, és befolyásolhatja a feldolgozási időt.

Ezután általában nem akarjuk blokkolni ezeket a szálakat, és ez nem blokkoló I / O API-k és aszinkron API-k használatát eredményezi, ami megzavarhatja a kódunkat.

Ellenkezőleg, a virtuális szálakat a JVM kezeli. Ezért azok a kiosztáshoz nincs szükség rendszerhívásra, és ők mentes az operációs rendszer kontextuskapcsolójától. Ezenkívül a virtuális szálak a hordozószálon futnak, ez az a tényleges kernelszál, amelyet a motorháztető alatt használnak. Ennek eredményeként, mivel mentesek vagyunk a rendszer kontextusváltójától, sokkal több ilyen virtuális szálat hozhatunk létre.

Ezután a virtuális szálak egyik legfontosabb tulajdonsága, hogy nem blokkolják a szállítószálunkat. Ezzel a virtuális szál blokkolása sokkal olcsóbb műveletté válik, mivel a JVM újabb virtuális szálat ütemez, a hordozó szál feloldása nélkül.

Végül nem kellene NIO vagy Async API-khoz fordulnunk. Ennek egy olvashatóbb, könnyebben érthető és hibakereső kódot kell eredményeznie. Mindazonáltal, a folytatás potenciálisan blokkolhatja a szállítószálat - konkrétan, amikor egy szál natív metódust hív és onnan hajt végre blokkoló műveleteket.

3. Új Thread Builder API

A Loom-ban megkaptuk az új építő API-t a cérna osztály, több gyári módszerrel együtt. Lássuk, hogyan hozhatunk létre szabványos és virtuális gyárakat, és hogyan használhatjuk fel őket a szálfuttatáshoz:

Futható printThread = () -> System.out.println (Thread.currentThread ()); ThreadFactory virtualThreadFactory = Thread.builder (). Virtual (). Factory (); ThreadFactory kernelThreadFactory = Thread.builder (). Factory (); Szál virtualThread = virtualThreadFactory.newThread (printThread); Szál kernelThread = kernelThreadFactory.newThread (printThread); virtualThread.start (); kernelThread.start ();

Itt van a fenti futás eredménye:

Téma [Thread-0,5, main] VirtualThread [, ForkJoinPool-1-worker-3, CarrierThreads]

Itt az első bejegyzés a szabvány Sztring kernel szál kimenete.

Most azt látjuk a kimenetben, hogy a virtuális szálnak nincs neve, és a Fork-Join készlet munkásszálán hajtja végre a CarrierThreads szálcsoport.

Amint láthatjuk, az alapul szolgáló megvalósítástól függetlenül az API megegyezik, és ez azt jelenti, hogy könnyen futtathatunk meglévő kódot a virtuális szálakon.

Emellett nem kell új API-t megtanulnunk a használatukhoz.

4. Virtuális szálkompozíció

Ez egy folytatás és ütemező hogy együtt alkotnak egy virtuális szálat. Most a felhasználói módú ütemezőnk lehet a Végrehajtó felület. A fenti példa megmutatta, hogy alapértelmezés szerint a ForkJoinPool.

Most, hasonlóan a rendszermaghoz - amely végrehajtható a CPU-n, majd parkolhat, újra ütemezhető, majd folytatja a végrehajtását - a folytatás egy végrehajtási egység, amely elindítható, majd leparkolható (hozható), újra ütemezhető és folytatható végrehajtása ugyanarról a helyről, ahol abbahagyta, és továbbra is a JVM kezeli, ahelyett, hogy az operációs rendszerre támaszkodna.

Ne feledje, hogy a folytatás egy alacsony szintű API, és a programozóknak magasabb szintű API-kat kell használniuk, mint például a készítő API-t a virtuális szálak futtatásához.

Ahhoz azonban, hogy bemutassuk, hogyan működik a motorháztető alatt, most futtatjuk a kísérleti folytatást:

var hatókör = new ContinuationScope ("C1"); var c = új folytatás (hatókör, () -> {System.out.println ("C1 indítás"); Continuation.yield (hatókör); System.out.println ("C1 vége";}); while (! c.isDone ()) {System.out.println ("Futtatás indítása ()"); c.run (); System.out.println ("Futtatás befejezése ()"); }

Itt van a fenti futás eredménye:

Futtatás indítása () C1 indítás befejezése () Futtatás indítása () C1 futás befejezése ()

Ebben a példában lefuttattuk a folytatást, és valamikor úgy döntöttünk, hogy leállítjuk a feldolgozást. Aztán miután újra futottunk, folytatásunk onnan folytatódott, ahol abbahagyta. A kimenet alapján látjuk, hogy a fuss() metódust kétszer hívták meg, de a folytatást egyszer elkezdték, majd a második menetben onnan folytatták, ahonnan abbahagyták.

A blokkolási műveleteket így kívánja feldolgozni a JVM. Miután megtörténik egy blokkolási művelet, a folytatás meghozza az eredményt, és a hordozószál blokkolatlan marad.

Tehát az történt, hogy a fő szálunk egy új veremkeretet hozott létre a fuss() módszerrel folytatta a végrehajtást. Majd a folytatás eredményét követően a JVM mentette a végrehajtás aktuális állapotát.

Ezután a fő szál folytatta a végrehajtását, mintha a fuss() módszer visszatért és folytatta a míg hurok. A második folytatás után fuss módszerrel a JVM visszaállította a fő szál állapotát arra a pontra, ahol a folytatás megadta és befejezte a végrehajtást.

5. Következtetés

Ebben a cikkben megvitattuk a kernel és a virtuális szál közötti különbséget. Ezután megmutattuk, hogyan használhatnánk a Project Loom új szálkészítő API-ját a virtuális szálak futtatásához.

Végül megmutattuk, mi a folytatás és hogyan működik a motorháztető alatt. A korai hozzáférésű virtuális gép ellenőrzésével tovább vizsgálhatjuk a Project Loom állapotát. Alternatív megoldásként felfedezhetünk többet a már szabványosított Java egyidejűségi API-k közül.