"Hallo Amigo!"
"Ik wil diep met je duiken met betrekking tot wait-notify. De wait-notify-methoden bieden een handig mechanisme voor interactie tussen threads. Ze kunnen ook worden gebruikt om complexe mechanismen op hoog niveau voor thread-interactie te bouwen."
"Ik zal beginnen met een klein voorbeeld. Stel dat we een programma hebben voor een server die verschillende taken moet uitvoeren die door gebruikers via een website zijn gemaakt. Gebruikers kunnen op verschillende tijdstippen verschillende taken toevoegen. De taken zijn arbeidsintensief, maar onze server is 8 -core processor aankan. Hoe moeten we de taken op de server uitvoeren?"
"Eerst maken we een groep werkthreads, zoveel als er processorkernen zijn. Elke thread kan op zijn eigen kern draaien: de threads zullen elkaar niet hinderen en de processorkernen niet stil zitten."
"Ten tweede maken we een wachtrij-object waar de taken van gebruikers worden toegevoegd. Verschillende soorten taken komen overeen met verschillende objecten, maar ze zullen allemaal de Runnable-interface implementeren, zodat ze kunnen worden uitgevoerd."
"Kun je me een voorbeeld geven van een taakobject?"
"Bekijken:"
class Factorial implements Runnable
{
public int n = 0;
public long result = 1;
public Factorial (int n)
{
this.n = n;
}
public void run()
{
for (int i = 2; i <= n; i++)
result *= i;
}
}
"Tot nu toe, zo goed."
"Geweldig. Laten we dan eens kijken hoe een wachtrij-object eruit moet zien. Wat kun je me daarover vertellen?"
"Het moet threadveilig zijn. Het wordt geladen met taakobjecten door een thread die ze van gebruikers ontvangt, en vervolgens worden de taken opgepikt door werkthreads."
"Ja. En wat als we een tijdje geen taken meer hebben?"
"Dan moeten de werkthreads wachten tot er meer zijn."
"Dat klopt. Stel je nu voor dat dit allemaal in één enkele wachtrij kan worden gebouwd. Bekijk het eens:"
public class JobQueue
{
ArrayList jobs = new ArrayList();
public synchronized void put(Runnable job)
{
jobs.add(job);
this.notifyAll();
}
public synchronized Runnable getJob()
{
while (jobs.size() == 0)
this.wait();
return jobs.remove(0);
}
}
"We hebben een getJob- methode die controleert of de takenlijst leeg is. De thread gaat dan slapen (wachten) totdat er iets in de lijst verschijnt."
"Er is ook de methode put , waarmee je een nieuwe taak aan de lijst kunt toevoegen. Zodra een nieuwe taak wordt toegevoegd, wordt de methode attendAll aangeroepen. Door deze methode aan te roepen, worden alle werkthreads wakker die in de getJob-methode in slaap zijn gevallen."
"Kun je je nog eens herinneren hoe de wacht- en meldingsmethoden werken?"
"De wait-methode wordt alleen aangeroepen binnen een gesynchroniseerd blok, op een mutex-object. In ons geval: dit. Bovendien gebeuren er twee dingen:
1) De draad valt in slaap.
2) De draad laat de mutex tijdelijk los (tot hij wakker wordt).
"Daarna kunnen andere threads het gesynchroniseerde blok binnengaan en diezelfde mutex verwerven."
"De methode notificationAll kan ook alleen worden aangeroepen binnen het gesynchroniseerde blok van een mutex-object. In ons geval: dit. Bovendien gebeuren er twee dingen:"
1) Alle threads die wachten op dit mutex-object worden gewekt.
2) Zodra de huidige thread het gesynchroniseerde blok verlaat, verwerft een van de ontwaakte threads de mutex en zet zijn werk voort. Wanneer het de mutex vrijgeeft, verwerft een andere ontwaakte thread de mutex, enz.
"Het lijkt erg op een bus. Je stapt in en wilt betalen, maar er is geen chauffeur. Dus val je in slaap. Uiteindelijk zit de bus vol, maar er is nog steeds niemand om de ritprijs aan te geven. Dan de chauffeur arriveert en zegt: «Vaarwel, alstublieft». En dit is het begin van..."
"Interessante vergelijking. Maar wat is een bus?"
"Julio legde dit uit. Er werden rare dingen gebruikt in de 21e eeuw."
GO TO FULL VERSION