A

– Szia Amigo!

"Szeretnék mélyen elmerülni Önnel a várni-értesítéssel kapcsolatban. A várakozás-értesítés metódusok kényelmes mechanizmust biztosítanak a szálak interakciójához. Használhatók összetett, magas szintű mechanizmusok létrehozására is a szálak interakciójához."

"Először egy kis példával kezdem. Tegyük fel, hogy van egy programunk egy szerverhez, amelynek különféle feladatokat kell végrehajtania a felhasználók által egy webhelyen keresztül. A felhasználók különböző időpontokban adhatnak hozzá különféle feladatokat. A feladatok erőforrás-igényesek, de a szerverünk 8 -core processzor képes megbirkózni. Hogyan végezzük el a feladatokat a szerveren?"

"Először is létrehozunk egy munkaszál-csoportot, ahány processzormag van. Mindegyik szál képes lesz a saját magján futni: a szálak nem zavarják egymást, és a processzormagok sem. ülj tétlenül."

"Másodszor létrehozunk egy sorobjektumot, amelybe a felhasználók feladatai kerülnek hozzáadásra. A különböző típusú feladatok különböző objektumoknak felelnek meg, de mindegyik megvalósítja a Runnable felületet, így futtatható."

– Mondana egy példát egy feladatobjektumra?

"Nézd meg:"

Osztály, amely n faktoriálist számít ki a run() metódus meghívásakor
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;
 }
}

"Eddig jó."

"Remek. Akkor vizsgáljuk meg, hogyan kell kinéznie egy sorobjektumnak. Mit tud mondani róla?"

"Szálbiztosnak kell lennie. Feladatobjektumokkal egy szál tölti be, amely fogadja azokat a felhasználóktól, majd a feladatokat a munkaszálak veszik fel."

"Igen. És mi van, ha egy időre kifogyunk a feladatokból?"

"Akkor a munkásszálaknak meg kell várniuk, amíg több lesz."

"Így van. Most képzelje el, hogy mindez egyetlen sorban is felépíthető. Nézze meg:"

Feladatsor. Ha nincsenek feladatok, akkor a szál elalszik, és megvárja, amíg megjelenik:
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);
 }
}

"Van egy getJob metódusunk, amely ellenőrzi, hogy a feladatlista üres-e. A szál ezután alvó állapotba kerül (vár), amíg valami megjelenik a listában."

"Létezik még a put metódus, amellyel új feladatot adhat a listához. Amint új feladatot adnak hozzá, a notifyAll metódus hívódik meg. Ennek a metódusnak a meghívása felébreszti az összes olyan dolgozó szálat, amely a getJob metóduson belül elaludt."

– Emlékszel még, hogyan működnek a várakozás és értesítés módszerei?

"A várakozás metódus csak szinkronizált blokkon belül, mutex objektumon hívódik meg. Esetünkben ez. Ráadásul két dolog történik:

1) A cérna elalszik.

2) A szál ideiglenesen feloldja a mutexet (amíg fel nem ébred).

"Ezt követően más szálak beléphetnek a szinkronizált blokkba, és megszerezhetik ugyanazt a mutexet."

"A notifyAll metódus is csak egy mutex objektum szinkronizált blokkján belül hívható meg. Esetünkben ez. Ráadásul két dolog történik:"

1) Minden szál, amely ezen a mutex objektumon várakozik, felébred.

2) Miután az aktuális szál kilép a szinkronizált blokkból, az egyik felébresztett szál megszerzi a mutexet, és folytatja munkáját. Amikor felszabadítja a mutexet, egy másik felébresztett szál megszerzi a mutexet stb.

"Nagyon hasonlít a buszhoz. Belépsz és ki akarod fizetni a viteldíjat, de nincs sofőr. Szóval "elalszol". Végül a busz tömve van, de még mindig nincs kinek megadni a viteldíjat. Aztán a sofőr megérkezik, és azt mondja: „Figyelj, kérlek!” És ez a kezdete…”

"Érdekes összehasonlítás. De mi az a busz?"

"Julio elmagyarázta ezt. Voltak ilyen furcsa dolgok, amelyeket a 21. században használtak."