Útmutató a Java szinkronizált kulcsszavához

1. Áttekintés

Ez a rövid cikk bevezető lesz a szinkronizált blokk a Java-ban.

Egyszerűen fogalmazva, egy több szálat tartalmazó környezetben versenyfeltétel akkor fordul elő, amikor két vagy több szál egyszerre próbálja frissíteni a mutábilis megosztott adatokat. A Java mechanizmust kínál a versenyfeltételek elkerülésére azáltal, hogy szinkronizálja a szál hozzáférését a megosztott adatokhoz.

Egy logikai darab, amelyet jelöltünk szinkronizált szinkronizált blokkká válik, csak egy szál végrehajtását engedélyezheti egy adott időpontban.

2. Miért szinkronizálás?

Vegyünk egy tipikus versenyfeltételt, ahol kiszámoljuk az összeget, és több szál hajtja végre a kiszámítja() módszer:

nyilvános osztály BaeldungSynchronizedMethods {private int sum = 0; public void kiszámítja () {setSum (getSum () + 1); } // szabványos beállítók és szerelők} 

Írjunk egy egyszerű tesztet:

@Test public void givenMultiThread_whenNonSyncMethod () {ExecutorService service = Executors.newFixedThreadPool (3); BaeldungSynchronizedMethods összegzés = new BaeldungSynchronizedMethods (); IntStream.range (0, 1000) .forEach (count -> service.submit (összegzés :: számítás)); service.awaitTermination (1000, TimeUnit.MILLISECONDS); assertEquals (1000, összegzés.getSum ()); }

Egyszerűen egy ExecutorService 3 szálas medencével a kiszámítja() 1000-szer.

Ha ezt sorosan hajtanánk végre, akkor a várható kimenet 1000 lenne, de többszálú végrehajtásunk szinte minden alkalommal kudarcot vall következetlen tényleges kimenettel, pl .:

java.lang.AssertionError: várható: de volt: at org.junit.Assert.fail (Assert.java:88) at org.junit.Assert.failNotEquals (Assert.java:834) ...

Ez az eredmény természetesen nem váratlan.

A versenyfeltételek elkerülésének egyszerű módja, ha a műveletet menetbiztonságossá teszi a szinkronizált kulcsszó.

3. Az Szinkronizált Kulcsszó

A szinkronizált kulcsszó különböző szinteken használható:

  • Példamódszerek
  • Statikus módszerek
  • Kód blokkok

Amikor a szinkronizált blokk, belsőleg a Java olyan monitort használ, amelyet monitorzárnak vagy belső zárnak is neveznek a szinkronizálás érdekében. Ezek a monitorok egy objektumhoz vannak kötve, így ugyanazon objektum összes szinkronizált blokkjának egyetlen szála lehet egyszerre.

3.1. Szinkronizált Példamódszerek

Egyszerűen adja hozzá a szinkronizált kulcsszó a metódus deklarációban a módszer szinkronizálásához:

public synchronized void synchronisedCalculate () {setSum (getSum () + 1); }

Figyeljük meg, hogy amint szinkronizáljuk a módszert, a tesztesemény átmegy, tényleges kimenete 1000:

@Test public void givenMultiThread_whenMethodSync () {ExecutorService service = Executors.newFixedThreadPool (3); SynchronizedMethods módszer = új SynchronizedMethods (); IntStream.range (0, 1000) .forEach (count -> service.submit (metódus :: synchronisedCalculate)); service.awaitTermination (1000, TimeUnit.MILLISECONDS); assertEquals (1000, method.getSum ()); }

A példamódszerek szinkronizált a módszert birtokló osztály példánya felett. Ami azt jelenti, hogy az osztály példányainként csak egy szál hajthatja végre ezt a módszert.

3.2. Szinkronizált Static Mód

A statikus módszerek szinkronizált akárcsak a példányos módszerek:

 nyilvános statikus szinkronizált void syncStaticCalculate () {staticSum = staticSum + 1; }

Ezek a módszerek szinkronizált a Osztály osztályhoz társított objektum, és mivel csak egy Osztály objektum létezik JVM-enként osztályonként, csak egy szál hajtható végre az a-ban statikus szinkronizált módszer osztályonként, függetlenül a meglévő példányok számától.

Teszteljük:

@Test public void givenMultiThread_whenStaticSyncMethod () {ExecutorService service = Executors.newCachedThreadPool (); IntStream.range (0, 1000) .forEach (count -> service.submit (BaeldungSynchronizedMethods :: syncStaticCalculate)); service.awaitTermination (100, TimeUnit.MILLISECONDS); assertEquals (1000, BaeldungSynchronizedMethods.staticSum); }

3.3. Szinkronizált Blokkok a módszereken belül

Néha nem a teljes módszert akarjuk szinkronizálni, hanem csak néhány utasítást benne. Ezt úgy lehet elérni alkalmazva blokkkal szinkronizálva:

public void performSynchronisedTask () {synchronized (this) {setCount (getCount () + 1); }}

Teszteljük a változást:

@Test public void givenMultiThread_whenBlockSync () {ExecutorService service = Executors.newFixedThreadPool (3); BaeldungSynchronizedBlocks synchronizedBlocks = új BaeldungSynchronizedBlocks (); IntStream.range (0, 1000) .forEach (count -> service.submit (synchronizedBlocks :: performSynchronisedTask)); service.awaitTermination (100, TimeUnit.MILLISECONDS); assertEquals (1000, synchronizedBlocks.getCount ()); }

Figyelje meg, hogy átadtunk egy paramétert ez hoz szinkronizált Blokk. Ez a monitor objektum, a blokkban lévő kód szinkronizálódik a monitor objektummal. Egyszerűen fogalmazva, monitorobjektumonként csak egy szál hajtható végre a kódblokk belsejében.

Abban az esetben, ha a módszer az statikus, az objektum hivatkozás helyett átadnánk az osztály nevét. Az osztály pedig a blokk szinkronizálásának monitorja lenne:

public static void performStaticSyncTask () {synchronized (SynchronisedBlocks.class) {setStaticCount (getStaticCount () + 1); }}

Teszteljük a blokkot a statikus módszer:

@Test public void givenMultiThread_whenStaticSyncBlock () {ExecutorService service = Executors.newCachedThreadPool (); IntStream.range (0, 1000) .forEach (count -> service.submit (BaeldungSynchronizedBlocks :: performStaticSyncTask)); service.awaitTermination (100, TimeUnit.MILLISECONDS); assertEquals (1000, BaeldungSynchronizedBlocks.getStaticCount ()); }

3.4. Visszatérés

A zár a szinkronizált módszerek és blokkok visszahat. Vagyis az aktuális szál ugyanezt megszerezheti szinkronizált rögzítse újra és újra, miközben tartja:

Objektumzár = new Object (); szinkronizált (zárolás) {System.out.println ("Első alkalommal szerzem be"); szinkronizált (zár) {System.out.println ("Újra belépés"); szinkronizált (zár) {System.out.println ("És újra"); }}}

Amint a fentiekből látható, amíg a szinkronizált blokk esetén ismételten megszerezhetjük ugyanazt a monitorzárat.

4. Következtetés

Ebben a gyors cikkben a szinkronizált kulcsszó a szál szinkronizálásához.

Azt is megvizsgáltuk, hogy a versenyfeltételek hogyan befolyásolhatják alkalmazásunkat, és hogy a szinkronizálás hogyan segít ezt elkerülni. Ha többet szeretne tudni a szálak biztonságáról a Java zárak használatával, olvassa el java.util.concurrent.Locks cikk.

Az oktatóanyag teljes kódja elérhető a GitHub oldalon.