De

"Hei, Amigo!"

"Jeg ønsker å dykke dypt med deg angående vent-varsling. Vent-varslingsmetodene gir en praktisk mekanisme for tråder å samhandle. De kan også brukes til å bygge komplekse høynivåmekanismer for trådsamhandling."

"Jeg starter med et lite eksempel. Tenk deg at vi har et program for en server som må utføre forskjellige oppgaver opprettet av brukere gjennom en nettside. Brukere kan legge til forskjellige oppgaver til forskjellige tider. Oppgavene er ressurskrevende, men vår server har 8 -kjerneprosessor kan klare seg. Hvordan skal vi utføre oppgavene på serveren?"

"Først vil vi lage en gruppe arbeidertråder, så mange som det er prosessorkjerner. Hver tråd vil kunne kjøre på sin egen kjerne: Trådene vil ikke forstyrre hverandre, og prosessorkjernene vil ikke sitte stille."

"For det andre vil vi lage et køobjekt der brukernes oppgaver vil bli lagt til. Ulike typer oppgaver vil tilsvare forskjellige objekter, men alle vil implementere Runnable-grensesnittet slik at de kan kjøres."

"Kan du gi meg et eksempel på et oppgaveobjekt?"

"Sjekk det ut:"

En klasse som beregner n faktorial når run()-metoden kalles
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;
 }
}

"Så langt så bra."

"Flott. Så la oss undersøke hvordan et køobjekt skal se ut. Hva kan du fortelle meg om det?"

"Den må være trådsikker. Den lastes med oppgaveobjekter av en tråd som mottar dem fra brukere, og deretter plukkes oppgavene opp av arbeidertråder."

"Japp. Og hva om vi går tom for oppgaver en stund?"

«Da bør arbeidertrådene vente til det er flere».

"Det stemmer. Tenk deg nå at alt dette kan bygges i en enkelt kø. Sjekk det ut:"

En oppgavekø. Hvis det ikke er noen oppgaver, sovner tråden og venter på at en dukker opp:
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- metode som sjekker om oppgavelisten er tom. Tråden går så i dvale (venter) til noe dukker opp i listen."

"Det er også put- metoden, som lar deg legge til en ny oppgave i listen. Så snart en ny oppgave er lagt til, kalles notifyAll- metoden. Å kalle denne metoden vekker alle arbeidertråder som sovnet inne i getJob-metoden."

"Kan du huske igjen hvordan vente- og varslingsmetodene fungerer?"

"Ventemetoden kalles bare inne i en synkronisert blokk, på et mutex-objekt. I vårt tilfelle: dette. Dessuten skjer to ting:

1) Tråden sovner.

2) Tråden frigjør mutexen midlertidig (til den våkner).

"Etter det kan andre tråder gå inn i den synkroniserte blokken og få den samme mutexen."

" NotifyAll -metoden kan også bare kalles inne i den synkroniserte blokken til et mutex-objekt. I vårt tilfelle: dette. Dessuten skjer to ting:"

1) Alle tråder som venter på dette mutex-objektet vekkes.

2) Når den nåværende tråden forlater den synkroniserte blokken, henter en av de vekkede trådene mutexen og fortsetter arbeidet. Når den slipper mutexen, får en annen vekket tråd mutexen osv.

"Den er veldig lik en buss. Du går inn og vil betale prisen, men det er ingen sjåfør. Så du «sovner". Etter hvert er bussen fullpakket, men det er fortsatt ingen å gi billett til. Så sjåføren kommer og sier: «Fare, please». Og dette er begynnelsen på..."

"Interessant sammenligning. Men hva er en buss?"

"Julio forklarte dette. Det var disse rare tingene som ble brukt i det 21. århundre."