CodeGym /Java Course /Module 2: Java-kern /Discussies zijn niet onafhankelijk! gesynchroniseerd!

Discussies zijn niet onafhankelijk! gesynchroniseerd!

Module 2: Java-kern
Niveau 12 , Les 1
Beschikbaar

"Hallo, Amigo! We hebben een wondermiddel - een remedie voor alle ziekten. Zoals we al hebben gezien, is ongecontroleerd wisselen van draad een probleem."

"Waarom kunnen de threads zelf niet beslissen wanneer ze naar de volgende thread moeten overschakelen? Alles doen wat ze moeten doen en dan aangeven: «Ik ben klaar!»?"

"Het zou een nog groter probleem zijn om threads zelf het schakelen te laten regelen. Stel dat je slecht geschreven code hebt en de thread geeft nooit de CPU over. Vroeger werkte het zo. En het was nogal een nachtmerrie."

"Oké. Dus wat is de oplossing?"

" Andere threads blokkeren.  Zo werkt het."

Het werd duidelijk dat threads elkaar hinderen wanneer ze gedeelde objecten en/of bronnen proberen te gebruiken . Net zoals we in het voorbeeld zagen met console-uitvoer: er is één console en alle threads worden ernaar uitgevoerd. Het is rommelig.

Dus werd er een bijzonder object uitgevonden: de mutex . Het is als een bordje op een badkamerdeur met de tekst "beschikbaar / bezet" . Het heeft twee statussen: het object is beschikbaar of bezet . Deze toestanden worden ook wel «vergrendeld» en «ontgrendeld» genoemd.

Wanneer een thread een object nodig heeft dat wordt gedeeld met andere threads, controleert het de mutex die aan het object is gekoppeld. Als de mutex ontgrendeld is, vergrendelt de thread deze (markeert deze als «bezet») en begint de gedeelde bron te gebruiken. Nadat de thread zijn werk heeft gedaan, wordt de mutex ontgrendeld (gemarkeerd als «beschikbaar»).

Als de thread het object wil gebruiken en de mutex is vergrendeld, slaapt de thread terwijl hij wacht. Wanneer de mutex uiteindelijk wordt ontgrendeld door de bezettende thread, zal onze thread deze onmiddellijk vergrendelen en beginnen te lopen. De analogie met een bordje op de badkamerdeur is perfect.

"Dus hoe werk ik met een mutex? Moet ik speciale objecten maken?"

"Het is veel eenvoudiger dan dat. De makers van Java hebben deze mutex ingebouwd in de klasse Object. Je hoeft hem dus niet eens te maken. Het maakt deel uit van elk object. Zo werkt het allemaal:"

Code Beschrijving
class MyClass
{
private String name1 = "Ally";
private String name2 = "Lena";

public void swap()
{
synchronized (this)
{
String s = name1;
name1 = name2;
name2 = s;
}
}
}
De swap-methode verwisselt de waarden van de naam1- en naam2-variabelen.

Wat kan er gebeuren als het vanuit twee threads tegelijk wordt aangeroepen?

Daadwerkelijke uitvoering van de code Code van de eerste thread Code van de tweede thread
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;
het komt neer op
De waarden van de variabelen werden twee keer verwisseld en keerden terug naar hun oorspronkelijke plaats.

Besteed aandacht aan het zoekwoord  gesynchroniseerd .

"Ja, wat betekent het?"

"Wanneer een thread een codeblok invoert dat is gemarkeerd als gesynchroniseerd, vergrendelt de Java-machine onmiddellijk de mutex van het object dat tussen haakjes wordt aangegeven na het woord gesynchroniseerd. Geen enkele andere thread kan dit blok binnenkomen totdat onze thread het verlaat. Zodra onze thread het verlaat het blok gemarkeerd als gesynchroniseerd, de mutex wordt onmiddellijk en automatisch ontgrendeld en zal beschikbaar zijn om te worden verkregen door een andere thread."

Als de mutex bezet is, staat onze thread stil en wacht tot deze vrijkomt.

"Zo eenvoudig en zo elegant. Dat is een mooie oplossing."

'Ja. Maar wat denk je dat er in dit geval zal gebeuren?'

Code Beschrijving
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;
}
}
}
De methoden swap en swap2 delen dezelfde mutex ( dit object).

Wat gebeurt er als een thread de swap-methode aanroept en een andere thread de swap2-methode aanroept?

"Aangezien de mutex hetzelfde is, zal de tweede thread moeten wachten tot de eerste thread het gesynchroniseerde blok verlaat. Er zullen dus geen problemen zijn met gelijktijdige toegang."

"Goed gedaan, Amigo! Dat is het juiste antwoord!"

Nu wil ik erop wijzen dat gesynchroniseerd kan worden gebruikt om niet alleen codeblokken te markeren, maar ook methoden. Dit is wat dat betekent:

Code Wat gebeurt er echt
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;
}
}
Opmerkingen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION