De

"Hej, Amigo!"

"Jag vill dyka djupt med dig angående vänta-avisering. Vänta-meddelande-metoderna ger en bekväm mekanism för trådar att interagera. De kan också användas för att bygga komplexa högnivåmekanismer för trådinteraktion."

"Jag börjar med ett litet exempel. Anta att vi har ett program för en server som måste utföra olika uppgifter skapade av användare via en webbplats. Användare kan lägga till olika uppgifter vid olika tidpunkter. Uppgifterna är resurskrävande, men vår servers 8 -core-processor klarar av. Hur ska vi utföra uppgifterna på servern?"

"Först skapar vi en grupp arbetstrådar, så många som det finns processorkärnor. Varje tråd kommer att kunna köras på sin egen kärna: Trådarna kommer inte att störa varandra, och processorkärnorna kommer inte att störa varandra. sitta sysslolös."

"För det andra skapar vi ett köobjekt där användarnas uppgifter kommer att läggas till. Olika typer av uppgifter kommer att motsvara olika objekt, men alla kommer att implementera Runnable-gränssnittet så att de kan köras."

"Kan du ge mig ett exempel på ett uppgiftsobjekt?"

"Kolla in det:"

En klass som beräknar n factorial när run()-metoden anropas
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;
 }
}

"Än så länge är allt bra."

"Jättebra. Låt oss då undersöka hur ett köobjekt ska se ut. Vad kan du berätta om det?"

"Det måste vara trådsäkert. Det laddas med uppgiftsobjekt av en tråd som tar emot dem från användare, och sedan plockas uppgifterna upp av arbetartrådar."

"Japp. Och tänk om vi får slut på uppgifter för en tid?"

"Då borde arbetartrådarna vänta tills det blir fler."

"Det stämmer. Föreställ dig nu att allt detta kan byggas i en enda kö. Kolla in det:"

En uppgiftskö. Om det inte finns några uppgifter, somnar tråden och väntar på att en ska dyka upp:
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);
 }
}

"Vi har en getJob -metod som kontrollerar om uppgiftslistan är tom. Tråden går sedan i vila (väntar) tills något dyker upp i listan."

"Det finns också put- metoden, som låter dig lägga till en ny uppgift i listan. Så snart en ny uppgift läggs till anropas notifyAll- metoden. Att anropa den här metoden väcker alla arbetartrådar som somnat i getJob-metoden."

"Kommer du ihåg hur vänte- och meddelandemetoderna fungerar igen?"

"Väntemetoden anropas bara inuti ett synkroniserat block, på ett mutex-objekt. I vårt fall: detta. Dessutom händer två saker:

1) Tråden somnar.

2) Tråden släpper tillfälligt mutexen (tills den vaknar).

"Efter det kan andra trådar gå in i det synkroniserade blocket och förvärva samma mutex."

" NotifyAll -metoden kan också bara anropas i det synkroniserade blocket av ett mutex-objekt. I vårt fall: detta. Dessutom händer två saker:"

1) Alla trådar som väntar på detta mutex-objekt väcks.

2) När den aktuella tråden lämnar det synkroniserade blocket, förvärvar en av de väckta trådarna mutexet och fortsätter sitt arbete. När den släpper mutexet, förvärvar en annan väckt tråd mutexet, etc.

"Det är väldigt likt en buss. Du går in och vill betala din biljett, men det finns ingen chaufför. Så du "somnar". Så småningom är bussen packad, men det finns fortfarande ingen att ge biljetten till. Sedan föraren. kommer och säger, "Fare, snälla". Och det här är början på..."

"Intressant jämförelse. Men vad är en buss?"

"Julio förklarade detta. Det fanns dessa konstiga saker som användes på 2000-talet."