Bevezetés
Tehát tudjuk, hogy a Java-nak vannak szálai. Erről a Jobb együtt: Java és a szál osztály című ismertetőben olvashat . I. rész – A végrehajtás szálai . A szálak szükségesek a párhuzamos munkavégzéshez. Ez nagyon valószínűvé teszi, hogy a szálak valamilyen módon kölcsönhatásba lépnek egymással. Nézzük meg, hogyan történik ez, és milyen alapvető eszközeink vannak.
Hozam
A Thread.yield() zavarba ejtő és ritkán használatos. Az interneten sokféleképpen leírják. Beleértve néhány embert, aki azt írja, hogy van néhány szálsor, amelyben egy szál a szálak prioritásai alapján ereszkedik le. Mások azt írják, hogy egy szál állapotát "Futó"-ról "Futható"-ra változtatja (annak ellenére, hogy nincs különbség ezek között az állapotok között, azaz a Java nem tesz különbséget közöttük). A valóság az, hogy mindez sokkal kevésbé ismert, de bizonyos értelemben egyszerűbb.
yield()
metódus dokumentációjában. Ha elolvasod, egyértelmű, hogy ayield()
metódus valójában csak néhány ajánlást ad a Java szálütemezőnek, hogy ennek a szálnak kevesebb végrehajtási időt kell adni. De hogy valójában mi történik, vagyis hogy az ütemező az ajánlás szerint cselekszik-e, és általában mit tesz, az a JVM megvalósításától és az operációs rendszertől függ. És ez más tényezőktől is függhet. Valószínűleg minden zűrzavar annak a ténynek köszönhető, hogy a Java nyelv fejlődésével újragondolták a többszálat. Olvasson többet az áttekintésben itt: A Java rövid bemutatása Thread.yield() .
Alvás
Egy szál aludhat a végrehajtása közben. Ez a legegyszerűbb interakció más szálakkal. A Java kódunkat futtató Java virtuális gépet futtató operációs rendszer saját szálütemezővel rendelkezik . Ez dönti el, hogy melyik szálat és mikor indítsa el. A programozó nem léphet kapcsolatba ezzel az ütemezővel közvetlenül a Java kódból, csak a JVM-en keresztül. Megkérheti az ütemezőt, hogy szüneteltesse a szálat egy időre, azaz altassa el. Bővebben ezekben a cikkekben olvashat: Thread.sleep() és How Multithreading működik . Azt is megnézheti, hogyan működnek a szálak a Windows operációs rendszerekben: A Windows Thread belső részei . És most lássuk a saját szemünkkel. Mentse el a következő kódot egy nevű fájlbaHelloWorldApp.java
:
class HelloWorldApp {
public static void main(String []args) {
Runnable task = () -> {
try {
int secToWait = 1000 * 60;
Thread.currentThread().sleep(secToWait);
System.out.println("Woke up");
} catch (InterruptedException e) {
e.printStackTrace();
}
};
Thread thread = new Thread(task);
thread.start();
}
}
Amint látja, van néhány feladatunk, amely 60 másodpercig vár, utána a program véget ér. A " " paranccsal lefordítjuk javac HelloWorldApp.java
, majd a " java HelloWorldApp
" paranccsal futtatjuk a programot. A legjobb, ha a programot külön ablakban indítjuk el. Például Windows alatt ez így van: start java HelloWorldApp
. A jps paranccsal kapjuk meg a PID-t (process ID), és a szálak listáját a " jvisualvm --openpid pid
: 
try {
TimeUnit.SECONDS.sleep(60);
System.out.println("Woke up");
} catch (InterruptedException e) {
e.printStackTrace();
}
Észrevetted, hogy InterruptedException
mindenhol intézkedünk? Értsük meg, miért.
Thread.interrupt()
Az a helyzet, hogy amíg egy szál vár/alszik, valaki meg akarja szakítani. Ebben az esetben egyInterruptedException
. Ez a mechanizmus azután jött létre, hogy a Thread.stop()
metódust elavultnak, azaz elavultnak és nemkívánatosnak nyilvánították. Ennek oka az volt stop()
, hogy a metódus meghívásakor a szál egyszerűen "megölték", ami nagyon kiszámíthatatlan volt. Nem tudhattuk, hogy a szál mikor áll le, és nem tudtuk garantálni az adatok konzisztenciáját. Képzelje el, hogy adatokat ír egy fájlba, miközben a szál megszakad. A Java készítői ahelyett, hogy megölték volna a szálat, úgy döntöttek, hogy logikusabb lenne azt mondani neki, hogy meg kell szakítani. Az, hogy miként reagálunk ezekre az információkra, maga a szál dönti el. További részletekért olvassa el a Miért elavult a Thread.stop című részt?az Oracle honlapján. Nézzünk egy példát:
public static void main(String []args) {
Runnable task = () -> {
try {
TimeUnit.SECONDS.sleep(60);
} catch (InterruptedException e) {
System.out.println("Interrupted");
}
};
Thread thread = new Thread(task);
thread.start();
thread.interrupt();
}
Ebben a példában nem várunk 60 másodpercet. Ehelyett azonnal megjelenik a „Megszakítva” felirat. Ez azért van, mert meghívtuk a interrupt()
metódust a szálon. Ez a módszer beállít egy belső jelzőt, az úgynevezett "megszakítási állapotot". Vagyis minden szálnak van egy belső jelzője, amely közvetlenül nem érhető el. De vannak natív módszereink a zászlóval való interakcióhoz. De nem ez az egyetlen módja. Lehet, hogy egy szál fut, nem vár valamire, egyszerűen csak műveleteket hajt végre. De arra számíthat, hogy mások egy adott időpontban be akarják fejezni a munkáját. Például:
public static void main(String []args) {
Runnable task = () -> {
while(!Thread.currentThread().isInterrupted()) {
// Do some work
}
System.out.println("Finished");
};
Thread thread = new Thread(task);
thread.start();
thread.interrupt();
}
A fenti példában a while
ciklus addig hajtódik végre, amíg a szál kívülről meg nem szakad. Ami a isInterrupted
zászlót illeti, fontos tudni, hogy ha elkapunk egy -t InterruptedException
, akkor az isInterrupted jelző visszaáll, majd isInterrupted()
false értéket ad vissza. A Thread osztálynak van egy statikus Thread.interrupted() metódusa is, amely csak az aktuális szálra vonatkozik, de ez a metódus visszaállítja a jelzőt false értékre! Bővebben ebben a Szálmegszakítás című fejezetben olvashat .
Csatlakozás (Várja meg, amíg egy másik szál befejeződik)
A legegyszerűbb típusú várakozás egy másik szál befejezésére vár.
public static void main(String []args) throws InterruptedException {
Runnable task = () -> {
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
System.out.println("Interrupted");
}
};
Thread thread = new Thread(task);
thread.start();
thread.join();
System.out.println("Finished");
}
Ebben a példában az új szál 5 másodpercig aludni fog. Ugyanakkor a főszál megvárja, amíg az alvó szál felébred és befejezi munkáját. Ha megnézi a szál állapotát a JVisualVM-ben, akkor az így fog kinézni: 
join
módszer meglehetősen egyszerű, mert ez csak egy Java kóddal rendelkező metódus, amely wait()
addig fut, amíg a szál, amelyen hívják, él. Amint a szál elhal (amikor befejezte a munkáját), a várakozás megszakad. És ez a join()
módszer varázsa. Tehát térjünk át a legérdekesebb dologra.
Monitor
A multithreading magában foglalja a monitor fogalmát. A monitor szó a 16. századi latinból származik az angolból, és jelentése "egy folyamat megfigyelésére, ellenőrzésére vagy folyamatos nyilvántartására használt műszer vagy eszköz". E cikk keretében megpróbáljuk lefedni az alapokat. Aki a részletekre vágyik, bátran vágjon bele a linkelt anyagokba. Útunkat a Java nyelvi specifikációval (JLS) kezdjük: 17.1. Szinkronizálás . A következőt írja ki:
lock()
illetve a segítségével felszabadíthatják unlock()
. Ezután megtaláljuk az oktatóanyagot az Oracle webhelyén: Intrinsic Locks and Synchronization. Ez az oktatóanyag azt mondja, hogy a Java szinkronizálása egy belső entitás köré épül, amelyet belső zárnak vagy monitorzárnak neveznek . Ezt a zárat gyakran egyszerűen " monitornak " nevezik . Azt is látjuk, hogy a Java minden objektumához belső zár tartozik. Olvassa el a Java - Intrinsic Locks and Synchronization című részt . Ezután fontos megérteni, hogyan lehet egy Java objektumot a monitorhoz társítani. A Java-ban minden objektumnak van egy fejléce, amely a programozó számára nem elérhető belső metaadatokat tárolja a kódból, de amelyre a virtuális gépnek szüksége van az objektumokkal való helyes működéshez. Az objektum fejléce tartalmaz egy "jelölőszót", amely így néz ki: 
https://edu.netbeans.org/contrib/slides/java-overview-and-java-se6.pdf
public class HelloWorld{
public static void main(String []args){
Object object = new Object();
synchronized(object) {
System.out.println("Hello World");
}
}
}
Itt az aktuális szál (az, amelyiken ezek a kódsorok végrehajtásra kerülnek) a synchronized
kulcsszó használatával megpróbálja használni aobject"\
változó a zár megszerzéséhez/megszerzéséhez. Ha senki más nem verseng a monitorért (azaz senki más nem futtat szinkronizált kódot ugyanazzal az objektummal), akkor a Java megpróbálhatja végrehajtani a "biased locking" nevű optimalizálást. Az objektum fejlécében a jelölőszóhoz hozzá kell adni egy releváns címkét és egy rekordot arról, hogy melyik szál birtokolja a monitor zárját. Ez csökkenti a monitor lezárásához szükséges többletköltséget. Ha a monitor korábban egy másik szál tulajdonában volt, akkor az ilyen zárolás nem elegendő. A JVM a következő típusú zárolásra vált: „alapzárás”. Összehasonlítás és csere (CAS) műveleteket használ. Ráadásul maga az objektumfejléc jelölőszava már nem tárolja a jelölőszót, hanem hivatkozást a tárolási helyére, és a címke megváltozik, így a JVM megérti, hogy alapvető zárolást használunk. Ha több szál verseng (mérkőzik) egy monitorért (az egyik megszerezte a zárolást, a másik pedig a zár feloldására vár), akkor a jelölőszóban lévő címke megváltozik, és a jelölőszó mostantól hivatkozást tárol a monitorra mint objektum – a JVM valamilyen belső entitása. A JDK bővítési javaslatában (JEP) leírtak szerint ez a helyzet a memória Native Heap területén helyet igényel az entitás tárolásához. A belső entitás memóriahelyére való hivatkozás az objektum fejlécének jelölőszójában kerül tárolásra. Így a monitor valójában egy mechanizmus a megosztott erőforrásokhoz való hozzáférés szinkronizálására több szál között. A JVM e mechanizmus több megvalósítása között vált. Tehát az egyszerűség kedvéért, amikor a monitorról beszélünk, valójában zárakról beszélünk. és egy másodperc a zár feloldására vár), majd a jelölőszóban lévő címke megváltozik, és a jelölőszó most objektumként tárolja a monitorra mutató hivatkozást – a JVM valamilyen belső entitását. A JDK bővítési javaslatában (JEP) leírtak szerint ez a helyzet a memória Native Heap területén helyet igényel az entitás tárolásához. A belső entitás memóriahelyére való hivatkozás az objektum fejlécének jelölőszójában kerül tárolásra. Így a monitor valójában egy mechanizmus a megosztott erőforrásokhoz való hozzáférés szinkronizálására több szál között. A JVM e mechanizmus több megvalósítása között vált. Tehát az egyszerűség kedvéért, amikor a monitorról beszélünk, valójában zárakról beszélünk. és egy másodperc a zár feloldására vár), majd a jelölőszóban lévő címke megváltozik, és a jelölőszó most objektumként tárolja a monitorra mutató hivatkozást – a JVM valamilyen belső entitását. A JDK bővítési javaslatában (JEP) leírtak szerint ez a helyzet a memória Native Heap területén helyet igényel az entitás tárolásához. A belső entitás memóriahelyére való hivatkozás az objektum fejlécének jelölőszójában kerül tárolásra. Így a monitor valójában egy mechanizmus a megosztott erőforrásokhoz való hozzáférés szinkronizálására több szál között. A JVM e mechanizmus több megvalósítása között vált. Tehát az egyszerűség kedvéért, amikor a monitorról beszélünk, valójában zárakról beszélünk. és a jelölőszó most objektumként tárolja a monitorra mutató hivatkozást – a JVM valamilyen belső entitását. A JDK bővítési javaslatában (JEP) leírtak szerint ez a helyzet a memória Native Heap területén helyet igényel az entitás tárolásához. A belső entitás memóriahelyére való hivatkozás az objektum fejlécének jelölőszójában kerül tárolásra. Így a monitor valójában egy mechanizmus a megosztott erőforrásokhoz való hozzáférés szinkronizálására több szál között. A JVM e mechanizmus több megvalósítása között vált. Tehát az egyszerűség kedvéért, amikor a monitorról beszélünk, valójában zárakról beszélünk. és a jelölőszó most objektumként tárolja a monitorra mutató hivatkozást – a JVM valamilyen belső entitását. A JDK bővítési javaslatában (JEP) leírtak szerint ez a helyzet a memória Native Heap területén helyet igényel az entitás tárolásához. A belső entitás memóriahelyére való hivatkozás az objektum fejlécének jelölőszójában kerül tárolásra. Így a monitor valójában egy mechanizmus a megosztott erőforrásokhoz való hozzáférés szinkronizálására több szál között. A JVM e mechanizmus több megvalósítása között vált. Tehát az egyszerűség kedvéért, amikor a monitorról beszélünk, valójában zárakról beszélünk. A belső entitás memóriahelyére való hivatkozás az objektum fejlécének jelölőszójában kerül tárolásra. Így a monitor valójában egy mechanizmus a megosztott erőforrásokhoz való hozzáférés szinkronizálására több szál között. A JVM e mechanizmus több megvalósítása között vált. Tehát az egyszerűség kedvéért, amikor a monitorról beszélünk, valójában zárakról beszélünk. A belső entitás memóriahelyére való hivatkozás az objektum fejlécének jelölőszójában kerül tárolásra. Így a monitor valójában egy mechanizmus a megosztott erőforrásokhoz való hozzáférés szinkronizálására több szál között. A JVM e mechanizmus több megvalósítása között vált. Tehát az egyszerűség kedvéért, amikor a monitorról beszélünk, valójában zárakról beszélünk. 
Szinkronizálva (vár a zárra)
Ahogy korábban láttuk, a "szinkronizált blokk" (vagy "kritikus szakasz") fogalma szorosan kapcsolódik a monitor fogalmához. Vessen egy pillantást egy példára:
public static void main(String[] args) throws InterruptedException {
Object lock = new Object();
Runnable task = () -> {
synchronized(lock) {
System.out.println("thread");
}
};
Thread th1 = new Thread(task);
th1.start();
synchronized(lock) {
for (int i = 0; i < 8; i++) {
Thread.currentThread().sleep(1000);
System.out.print(" " + i);
}
System.out.println(" ...");
}
}
Itt a főszál először átadja a feladat objektumot az új szálnak, majd azonnal megszerzi a zárolást és egy hosszú műveletet hajt végre vele (8 másodperc). Ez idő alatt a feladat nem tud továbbhaladni, mert nem tud belépni a synchronized
blokkba, mert a zár már megvan. Ha a szál nem tudja elérni a zárat, akkor vár a monitorra. Amint megkapja a zárolást, folytatja a végrehajtást. Amikor egy szál kilép a monitorból, feloldja a zárat. A JVisualVM-ben ez így néz ki: 
th1.getState()
Az utasítás a for ciklusban a BLOCKED értéket adja vissza , mert amíg a ciklus fut, az lock
objektum monitorát a szál foglalja el main
, a th1
szál pedig blokkolva van, és nem folytathatja a zárolás feloldásáig. A szinkronizált blokkok mellett egy egész metódus szinkronizálható. Például itt van egy metódus az osztályból HashTable
:
public synchronized int size() {
return count;
}
Ezt a módszert egy adott időpontban csak egy szál hajtja végre. Valóban szükségünk van a zárra? Igen, szükségünk van rá. Példánymetódusok esetén a "this" objektum (aktuális objektum) zárként működik. Érdekes vita folyik itt erről a témáról: Van-e előnye a szinkronizált módszer használatának szinkronizált blokk helyett? . Ha a metódus statikus, akkor a zár nem a "this" objektum lesz (mivel a statikus metódushoz nincs "this" objektum), hanem egy osztály objektum (például ) Integer.class
.
Várjon (monitorra vár). notify() és notifyAll() metódusok
A Thread osztálynak van egy másik várakozási metódusa, amely egy monitorhoz van társítva.sleep()
A és a -val ellentétben join()
ez a módszer nem hívható egyszerűen. A neve wait()
. A wait
metódust a monitorhoz társított objektum hívja meg, amelyre várni akarunk. Lássunk egy példát:
public static void main(String []args) throws InterruptedException {
Object lock = new Object();
// The task object will wait until it is notified via lock
Runnable task = () -> {
synchronized(lock) {
try {
lock.wait();
} catch(InterruptedException e) {
System.out.println("interrupted");
}
}
// After we are notified, we will wait until we can acquire the lock
System.out.println("thread");
};
Thread taskThread = new Thread(task);
taskThread.start();
// We sleep. Then we acquire the lock, notify, and release the lock
Thread.currentThread().sleep(3000);
System.out.println("main");
synchronized(lock) {
lock.notify();
}
}
A JVisualVM-ben ez így néz ki: 
wait()
és notify()
metódusok a következőhöz vannak társítva java.lang.Object
. Furcsának tűnhet, hogy a szálakhoz kapcsolódó metódusok vannak az Object
osztályban. De ennek oka most kiderül. Emlékszel, hogy a Java-ban minden objektumnak van fejléce. A fejléc különféle háztartási információkat tartalmaz, beleértve a monitorral kapcsolatos információkat, azaz a zár állapotát. Ne feledje, hogy minden objektum vagy osztálypéldány egy belső entitáshoz van társítva a JVM-ben, amelyet belső zárnak vagy monitornak neveznek. A fenti példában a feladatobjektum kódja azt jelzi, hogy megadjuk az objektumhoz társított monitor szinkronizált blokkját lock
. Ha sikerül megszereznünk a zárat ehhez a monitorhoz, akkorwait()
nak, nek hívják. A feladatot végrehajtó szál felszabadítja az lock
objektum monitorát, de belép a szálak sorába, amelyek értesítésre várnak az lock
objektum monitorától. Ezt a szálsort WAIT SET-nek nevezik, ami jobban tükrözi a célját. Vagyis inkább egy készlet, mint egy sor. A main
szál létrehoz egy új szálat a feladatobjektummal, elindítja, és vár 3 másodpercet. Ez nagyon valószínűvé teszi, hogy az új szál meg tudja szerezni a zárolást a main
szál előtt, és bekerüljön a monitor sorába. Ezt követően main
maga a szál belép az lock
objektum szinkronizált blokkjába, és a monitor segítségével szálértesítést hajt végre. Az értesítés elküldése után a main
szál felszabadítja alock
lock
az objektum monitorját, és az új szál, amely korábban az objektum monitorjának felszabadítására várt , folytatja a végrehajtást. Lehetséges értesítést küldeni csak egy szálnak ( notify()
), vagy egyidejűleg a sorban lévő összes szálnak ( notifyAll()
). Bővebben itt: A notify() és a notifyAll() közötti különbség a Java-ban . Fontos megjegyezni, hogy az értesítési sorrend a JVM megvalósítási módjától függ. Bővebben itt: Hogyan lehet megoldani az éhezést a notify és notifyAll segítségével? . A szinkronizálás objektum megadása nélkül is végrehajtható. Ezt akkor teheti meg, ha egy teljes metódust szinkronizál, nem pedig egyetlen kódblokkot. Például statikus metódusok esetén a zár egy Class objektum lesz (a következőn keresztül szerezhető be .class
):
public static synchronized void printA() {
System.out.println("A");
}
public static void printB() {
synchronized(HelloWorld.class) {
System.out.println("B");
}
}
A zárak használatában mindkét módszer azonos. instance
Ha egy metódus nem statikus, akkor a szinkronizálás az aktuális , azaz a segítségével történik this
. Mellesleg, korábban azt mondtuk, hogy a getState()
módszerrel lekérheti egy szál állapotát. Például a sorban lévő, figyelőre váró szál esetében az állapot VÁRAKOZÁS vagy TIMED_WAITING lesz, ha a wait()
metódus időtúllépést adott meg. 
https://stackoverflow.com/questions/36425942/what-is-the-lifecycle-of-thread-in-java
A szál életciklusa
Egy szál állapota élete során megváltozik. Valójában ezek a változások magukban foglalják a szál életciklusát. Amint létrejön egy szál, állapota ÚJ. Ebben az állapotban az új szál még nem fut, és a Java szálütemező még nem tud róla semmit. Ahhoz, hogy a szálütemező megismerje a szálat, meg kell hívnia athread.start()
metódust. Ezután a szál FUTTATÁS állapotba kerül. Az interneten sok helytelen diagram található, amelyek megkülönböztetik a "Futtatható" és a "Futó" állapotokat. De ez tévedés, mert a Java nem tesz különbséget a "munkára kész" (futható) és a "dolgozó" (futó) között. Ha egy szál él, de nem aktív (nem futtatható), akkor a következő két állapot egyikében van:
- BLOKKOLVA — várakozás a kritikus szakaszba, azaz egy
synchronized
blokkba való belépésre. - VÁRAKOZÁS – vár egy másik szálra, amely megfelel valamilyen feltételnek.
getState()
módszert. A szálaknak van egy isAlive()
metódusa is, amely igazat ad vissza, ha a szál nem TERMINÁLT.
LockSupport és menetparkoló
A Java 1.6-tól kezdve megjelent egy érdekes mechanizmus, a LockSupport .
park()
azonnal visszatér, ha az engedély rendelkezésre áll, és az engedélyt a folyamat során felhasználja. Ellenkező esetben blokkol. A módszer meghívásával unpark
elérhetővé válik az engedély, ha az még nem elérhető. Csak 1 engedély van. A Java dokumentáció LockSupport
az Semaphore
osztályra hivatkozik. Nézzünk egy egyszerű példát:
import java.util.concurrent.Semaphore;
public class HelloWorldApp{
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(0);
try {
semaphore.acquire();
} catch (InterruptedException e) {
// Request the permit and wait until we get it
e.printStackTrace();
}
System.out.println("Hello, World!");
}
}
Ez a kód mindig várni fog, mert most a szemafornak 0 engedélye van. És amikor acquire()
a kód be van hívva (azaz engedélyt kér), a szál megvárja, amíg megkapja az engedélyt. Mivel várunk, kezelnünk kell InterruptedException
. Érdekes módon a szemafor külön szálállapotot kap. Ha megnézzük a JVisualVM-et, látni fogjuk, hogy az állapot nem "Várj", hanem "Park". 
public static void main(String[] args) throws InterruptedException {
Runnable task = () -> {
// Park the current thread
System.err.println("Will be Parked");
LockSupport.park();
// As soon as we are unparked, we will start to act
System.err.println("Unparked");
};
Thread th = new Thread(task);
th.start();
Thread.currentThread().sleep(2000);
System.err.println("Thread state: " + th.getState());
LockSupport.unpark(th);
Thread.currentThread().sleep(2000);
}
A szál állapota VÁRAKOZÁS lesz, de a JVisualVM különbséget tesz wait
a synchronized
kulcsszó és park
az LockSupport
osztály között. Miért olyan fontos ez LockSupport
? Ismét a Java dokumentációhoz fordulunk, és megnézzük a WAITING szál állapotát. Amint látja, csak háromféleképpen lehet bekerülni. Ezek közül kettő wait()
a és join()
. A harmadik pedig az LockSupport
. A Java-ban a zárak t-re is építhetők, LockSuppor
és magasabb szintű eszközöket kínálnak. Próbáljunk meg egyet használni. Például nézze meg ReentrantLock
:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class HelloWorld{
public static void main(String []args) throws InterruptedException {
Lock lock = new ReentrantLock();
Runnable task = () -> {
lock.lock();
System.out.println("Thread");
lock.unlock();
};
lock.lock();
Thread th = new Thread(task);
th.start();
System.out.println("main");
Thread.currentThread().sleep(2000);
lock.unlock();
}
}
Csakúgy, mint az előző példákban, itt is minden egyszerű. Az lock
objektum arra vár, hogy valaki felszabadítsa a megosztott erőforrást. Ha megnézzük a JVisualVM-et, látni fogjuk, hogy az új szál addig parkolva lesz, amíg a main
szál fel nem oldja a zárolást. A zárolásokról itt olvashat bővebben: Java 8 StampedLocks vs. ReadWriteLocks és Synchronized and Lock API Java-ban. A zárolások megvalósításának jobb megértése érdekében hasznos elolvasni a Phaserről ebben a cikkben: Útmutató a Java Phaserhez . És ha a különféle szinkronizálókról beszélünk, el kell olvasnia a DZone The Java Synchronizers című cikkét .
Következtetés
Ebben az áttekintésben megvizsgáltuk a szálak Java-ban való interakciójának fő módjait. Kiegészítő anyag:- Jobb együtt: Java és a Thread osztály. I. rész – A végrehajtás szálai
- https://dzone.com/articles/the-java-synchronizers
- https://www.javatpoint.com/java-multithreading-interview-questions
GO TO FULL VERSION