CodeGym /Java blog /Véletlen /Szálszinkronizálás. A szinkronizált operátor
John Squirrels
Szint
San Francisco

Szálszinkronizálás. A szinkronizált operátor

Megjelent a csoportban
Szia! Ma továbbra is megvizsgáljuk a többszálú programozás jellemzőit, és beszélünk a szálak szinkronizálásáról. Szálszinkronizálás.  A szinkronizált operátor - 1

Mi a szinkronizálás a Java nyelven?

A programozási tartományon kívül olyan elrendezést jelent, amely lehetővé teszi két eszköz vagy program együttműködését. Például egy okostelefon és egy számítógép szinkronizálható egy Google-fiókkal, egy webhely-fiók pedig szinkronizálható a közösségi hálózati fiókokkal, így bejelentkezhet velük. A szálszinkronizálásnak hasonló jelentése van: ez egy olyan elrendezés, amelyben a szálak kölcsönhatásba lépnek egymás. Az előző leckéken szálaink külön éltek és működtek egymástól. Az egyik számítást végzett, a másik aludt, a harmadik pedig megjelenített valamit a konzolon, de nem léptek kapcsolatba. A valós programokban ritkák az ilyen helyzetek. Több szál is képes aktívan dolgozni és módosítani ugyanazt az adatkészletet. Ez problémákat okoz. Képzelje el, hogy több szál szöveget ír ugyanarra a helyre, például egy szövegfájlba vagy a konzolba. Ebben az esetben a fájl vagy konzol megosztott erőforrássá válik. A szálak nincsenek tudatában egymás létezésének, ezért egyszerűen mindent leírnak a szálütemező által számukra kijelölt időben. Egy közelmúltbeli leckében láthattunk példát arra, hogy ez hová vezet. Most emlékezzünk rá: Szálszinkronizálás.  A szinkronizált operátor - 2Az ok abban rejlik, hogy a szálak egy megosztott erőforrással (a konzollal) működnek anélkül, hogy összehangolnák tevékenységeiket. Ha a szálütemező időt rendel a Thread-1-hez, akkor azonnal mindent a konzolra ír. Nem számít, hogy milyen más szálakat sikerült megírni vagy még nem sikerült megírni. Az eredmény, amint látja, lehangoló. Ezért vezettek be egy speciális fogalmat, a mutex-et (kölcsönös kizárást) a többszálú programozásba. A mutex céljaegy olyan mechanizmus létrehozása, amellyel egy adott időpontban csak egy szál férhet hozzá egy objektumhoz. Ha az 1. szál megszerzi az A objektum mutexét, a többi szál nem fogja tudni elérni és módosítani az objektumot. A többi szálnak meg kell várnia, amíg az A objektum mutexe felszabadul. Íme egy példa az életből: képzeld el, hogy te és 10 másik idegen részt veszel egy gyakorlaton. Felváltva ki kell fejeznie gondolatait, és meg kell beszélnie valamit. De mivel először látjátok egymást, hogy ne szakítsátok meg folyamatosan egymást és ne legyetek dühbe gurulva, "beszélő labdát" használtok: csak az tud beszélni, akinek a labdája van. Így a végén egy jó és gyümölcsöző beszélgetés lesz. Lényegében a labda egy mutex. Ha egy objektum mutexje az egyik szál kezében van, a többi szál nem tud működni az objektummal.Objectosztály, ami azt jelenti, hogy a Java-ban minden objektumnak van egy.

Hogyan működik a szinkronizált operátor

Ismerkedjünk meg egy új kulcsszóval: szinkronizált . Egy bizonyos kódblokk megjelölésére szolgál. Ha egy kódblokk meg van jelölve a kulcsszóval synchronized, akkor azt a blokkot egyszerre csak egy szál hajthatja végre. A szinkronizálás többféleképpen is megvalósítható. Például egy teljes metódus szinkronizálásának deklarálásával:

public synchronized void doSomething() {

   // ...Method logic
}
Vagy írjon egy kódblokkot, ahol a szinkronizálás valamilyen objektum segítségével történik:

public class Main {

   private Object obj = new Object();

   public void doSomething() {

       // ...Some logic available simultaneously to all threads

       synchronized (obj) {

           // Logic available to just one thread at a time
       }
   }
}
A jelentés egyszerű. Ha egy szál a kulcsszóval megjelölt kódblokk belsejébe kerül synchronized, akkor azonnal rögzíti az objektum mutexét, és az összes többi szál, amely ugyanabba a blokkba vagy metódusba próbál belépni, kénytelen megvárni, amíg az előző szál befejezi a munkáját és felszabadítja a monitort. Szálszinkronizálás.  A szinkronizált operátor - 3Apropó! A kurzus során már láthatott példákat a következőre synchronized, de ezek másképp néztek ki:

public void swap()
{
   synchronized (this)
   {
       // ...Method logic
   }
}
A téma új számodra. És természetesen zavarok lesznek a szintaxissal. Tehát azonnal jegyezze meg, nehogy később összezavarjon a különböző írásmódok miatt. A két írásmód ugyanazt jelenti:

public void swap() {

   synchronized (this)
   {
       // ...Method logic
   }
}


public synchronized void swap() {

   }
}
Az első esetben a metódus megadása után azonnal létrehoz egy szinkronizált kódblokkot. thisAz objektum, azaz az aktuális objektum szinkronizálja . A második példában pedig alkalmazza a synchronizedkulcsszót a teljes metódusra. Ez szükségtelenné teszi a szinkronizáláshoz használt objektum kifejezett megjelölését. Mivel a teljes metódus a kulcsszóval van megjelölve, a metódus automatikusan szinkronizálva lesz az osztály összes példányával. Nem merülünk bele abba a vitába, hogy melyik út a jobb. Egyelőre válaszd azt a módot, amelyik a legjobban tetszik :) A lényeg az, hogy ne feledd: egy metódust csak akkor deklarálhatsz szinkronizáltnak, ha az összes logikáját egyszerre csak egy szál hajtja végre. Hiba lenne például a következő doSomething()metódust szinkronizálni:

public class Main {

   private Object obj = new Object();

   public void doSomething() {

       // ...Some logic available simultaneously to all threads

       synchronized (obj) {

           // Logic available to just one thread at a time
       }
   }
}
Amint látható, a metódus egy része olyan logikát tartalmaz, amely nem igényel szinkronizálást. Ezt a kódot egyszerre több szál is futtathatja, és az összes kritikus hely külön blokkban van elkülönítve synchronized. És még egy dolog. Vizsgáljuk meg alaposan a példánkat a névcserével járó leckéből:

public void swap()
{
   synchronized (this)
   {
       // ...Method logic
   }
}
Megjegyzés: a szinkronizálás a segítségével történikthis. Vagyis egy adottMyClassobjektum használatával. Tegyük fel, hogy van 2 szálunk (Thread-1ésThread-2) és csak egyMyClass myClassobjektumunk. Ebben az esetben, haThread-1meghívja amyClass.swap()metódust, az objektum mutexje foglalt lesz, és amikor megpróbálja meghívni amyClass.swap()metódustThread-2, lefagy, amíg a mutex feloldására vár. Ha lesz 2 szálunk és 2MyClassobjektumunk (myClass1ésmyClass2), akkor szálaink könnyen egyidejűleg végrehajthatják a szinkronizált metódusokat különböző objektumokon. Az első szál ezt hajtja végre:

myClass1.swap();
A második ezt hajtja végre:

myClass2.swap();
Ebben az esetben a metóduson synchronizedbelüli kulcsszó swap()nem befolyásolja a program működését, mivel a szinkronizálás egy adott objektum segítségével történik. És az utóbbi esetben 2 objektumunk van. Így a szálak nem okoznak problémát egymásnak. Végül is két objektumnak 2 különböző mutexe van, és az egyik megszerzése független a másik megszerzésétől .

A szinkronizálás sajátosságai statikus módszerekben

De mi van akkor, ha statikus metódust kell szinkronizálnia ?

class MyClass {
   private static String name1 = "Ally";
   private static String name2 = "Lena";

   public static synchronized void swap() {
       String s = name1;
       name1 = name2;
       name2 = s;
   }

}
Nem világos, hogy a mutex milyen szerepet fog játszani itt. Végül is már megállapítottuk, hogy minden objektumnak van mutexe. De a probléma az, hogy a metódus meghívásához nincs szükségünk objektumokra MyClass.swap(): a metódus statikus! Szóval mi a következő? :/ Itt tulajdonképpen nincs is gond. A Java készítői mindenről gondoskodtak :) Ha egy kritikus párhuzamos logikát tartalmazó metódus statikus, akkor a szinkronizálás osztályszinten történik. A nagyobb áttekinthetőség érdekében a fenti kódot a következőképpen írhatjuk át:

class MyClass {
   private static String name1 = "Ally";
   private static String name2 = "Lena";

   public static void swap() {

       synchronized (MyClass.class) {
           String s = name1;
           name1 = name2;
           name2 = s;
       }
   }

}
Ezt elvileg magad is gondolhattad volna: Mivel nincsenek objektumok, a szinkronizálási mechanizmust valahogy bele kell sütni magába az osztályba. És ez a helyzet: osztályokat használhatunk a szinkronizáláshoz.
Hozzászólások
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION