"Helló, Amigo! Van egy csodaszerünk – minden betegségre gyógyír. Mint már láttuk, az ellenőrizetlen szálváltás problémát jelent."

"Miért nem tudják maguk a szálak eldönteni, hogy mikor váltsanak a következő szálra? Tegyenek meg mindent, amit meg kell tenniük, majd jelezzék: «Kész vagyok!»?

"Még nagyobb probléma lenne, ha a szálak maguk irányítsák a váltást. Tegyük fel, hogy valami rosszul megírt kódja van, és a szál soha nem adja fel a CPU-t. Régen ez így működött. És elég rémálom volt."

"Rendben. Szóval mi a megoldás?"

" Más szálak blokkolása.  Ez így működik."

Világossá vált, hogy a szálak zavarják egymást, amikor megosztott objektumokat és/vagy erőforrásokat próbálnak használni . Ahogy a példában is láttuk a konzol kimeneténél: van egy konzol, és az összes szál arra kerül. Ez rendetlen.

Feltaláltak tehát egy különleges tárgyat: a mutexet . Olyan ez, mint egy tábla a fürdőszobaajtón, amelyen az áll, hogy «rendelkezésre áll / foglalt» . Két állapota van: az objektum elérhető vagy foglalt . Ezeket az állapotokat „zártnak” és „feloldottnak” is nevezik.

Ha egy szálnak más szálakkal megosztott objektumra van szüksége, akkor ellenőrzi az objektumhoz társított mutexet. Ha a mutex fel van oldva, akkor a szál zárolja ("foglaltnak" jelöli), és elkezdi használni a megosztott erőforrást. Miután a szál elvégezte a dolgát, a mutex feloldódik ("elérhető"-ként van megjelölve).

Ha a szál használni akarja az objektumot, és a mutex zárolva van, akkor a szál elalszik, amíg vár. Amikor a mutexet a megszálló szál végre feloldja, a mi szálunk azonnal lezárja és futni kezd. Tökéletes a hasonlat a fürdőszobaajtó táblájával.

"Szóval hogyan dolgozzak egy mutex-szel? Kell-e speciális objektumokat létrehoznom?"

"Ennél sokkal egyszerűbb. A Java készítői beépítették ezt a mutexet az Object osztályba. Így nem is kell létrehoznia. Minden objektum része. Így működik az egész:"

Kód Leírás
class MyClass
{
private String name1 = "Ally";
private String name2 = "Lena";

public void swap()
{
synchronized (this)
{
String s = name1;
name1 = name2;
name2 = s;
}
}
}
A swap metódus felcseréli a név1 és név2 változók értékeit.

Mi történhet, ha egyszerre két szálból hívják?

Tényleges kódvégrehajtás Az első szál kódja A második szál kódja
String s1 = name1; //Ally
name1 = name2; //Lena
name2 = s1; //Ally

String s2 = name1; //Lena
name1 = name2; //Ally
name2 = s2; //Lena
String s1 = name1;
name1 = name2;
//other thread is running
name2 = s1;
//the thread waits until the mutex is unlocked

String s2 = name1;
name1 = name2;
//other thread is running
//other thread is running
name2 = s2;
Alsó vonal
A változók értékeit kétszer felcseréltük, visszaállva az eredeti helyükre.

Ügyeljen a  szinkronizált kulcsszóra .

– Igen, mit jelent?

"Amikor egy szál belép egy szinkronizáltként megjelölt kódblokkba, a Java gép azonnal zárolja a szinkronizált szó után zárójelben jelzett objektum mutexét. Más szál nem léphet be ebbe a blokkba, amíg a mi szálunk ki nem hagyja. Amint a szálunk elhagyja a szinkronizált blokk esetén a mutex azonnal és automatikusan feloldódik, és elérhető lesz egy másik szál számára."

Ha a mutex foglalt, akkor a szálunk megáll, és várja, hogy felszabaduljon.

"Olyan egyszerű és olyan elegáns. Ez egy gyönyörű megoldás."

– Igen. De szerinted mi fog történni ebben az esetben?

Kód Leírás
class MyClass
{
private String name1 = "Ally";
private String name2 = "Lena";

public void swap()
{
synchronized (this)
{
String s = name1;
name1 = name2;
name2 = s;
}
}

public void swap2()
{
synchronized (this)
{
String s = name1;
name1 = name2;
name2 = s;
}
}
}
A swap és a swap2 metódusok ugyanazon a mutexen ( ez az objektum) osztoznak.

Mi történik, ha az egyik szál a swap metódust, a másik pedig a swap2 metódust?

"Mivel a mutex ugyanaz, a második szálnak meg kell várnia, amíg az első szál elhagyja a szinkronizált blokkot. Így nem lesz probléma az egyidejű hozzáféréssel."

"Jól van, Amigo! Ez a helyes válasz!"

Most szeretném felhívni a figyelmet arra, hogy a szinkronizálással nem csak kódblokkok, hanem metódusok is megjelölhetők. Ez a következőket jelenti:

Kód Mi történik valójában
class MyClass
{
private static String name1 = "Ally";
private static String name2 = "Lena";

public synchronized void swap()
{
String s = name1;
name1 = name2;
name2 = s;
}

public static synchronized void swap2()
{
String s = name1;
name1 = name2;
name2 = s;
}
}
class MyClass
{
private static String name1 = "Ally";
private static String name2 = "Lena";

public void swap()
{
synchronized (this)
{
String s = name1;
name1 = name2;
name2 = s;
}
}

public static void swap2()
{
synchronized (MyClass.class)
{
String s = name1;
name1 = name2;
name2 = s;
}
}