"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 |
---|---|
|
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 |
---|---|---|
|
|
|
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 |
---|---|
|
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 |
---|---|
|
|
GO TO FULL VERSION