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