Synchronizace v Java

Co je to Synchronizace v Java?

In Java, synchronizace označuje schopnost řídit přístup více vláken k libovolnému sdílenému prostředku. Je to ideální možnost, kdy chceme povolit přístup ke sdílenému prostředku pouze jednomu vláknu.

Tento přístup k provádění se obvykle nazývá „asynchronní“ programování. Na těchto procesorech jsou také vlákna, což jsou lehké procesy, které mohou provádět instrukce současně.

Druhy Synchronizace

Existují dva typy metod synchronizace Java:

1) Synchronizace procesů

2) Synchronizace vláken.

Pojďme studovat vlákno a Synchronizace procesů podrobně.

Synchronizace procesu: Zvládá synchronizaci mezi programy. Například programy jako `Microsoft Word` a `Acrobat reader` běží jako samostatné procesy.

Synchronizace vláken: Současné provádění kritického zdroje dvěma nebo více vlákny se nazývá vlákno Synchronizace. Můžete být dále seskupeni k vzájemně se vylučující komunikaci a komunikaci mezi vlákny.

Co je Lock in Java?

Zavřít Java je postaven na vnitřní entitě známé jako monitor nebo zámek. Ke všem objektům je přidružen zámek. Takže vlákno, které potřebuje konzistentní přístup k polím objektu, musí získat zámek objektu, než k nim přistoupí, a uvolní zámek, když je práce hotová. Tím je zajištěno, že ke sdíleným datům přistupuje vždy pouze jedno vlákno.

Vícevláknový program se synchronizací

Vícevláknový program je metoda nebo blok chráněný před rušením z jiných vláken sdílejících stejný zdroj uvedený pomocí klíčového slova `synchronized`.

Pomocí synchronizované metody

Každá metoda, která je deklarována jako synchronizovaná, je známá jako synchronizovaná metoda. Používá se také k uzamčení objektu pro jakýkoli sdílený prostředek. Takže, když vlákno vyvolá synchronizovanou metodu. Automaticky převezme zámek pro daný objekt a uvolní jej, když dokončí svůj úkol.

Poznámka: Synchronizované klíčové slovo nemůže pracovat s třídami a proměnnými. S klíčovým slovem lze použít pouze metody a bloky.

Proč používat Syncronizovaná metoda?

  • Používá se k uzamčení objektu pro jakékoli sdílené prostředky.
  • Objekt získá zámek při každém volání synchronizované metody.
  • Zámek se neuvolní, dokud vlákno nedokončí svou funkci

Syntaxe:

Acess_modifiers synchronized return_type method_name (Method_Parameters) {
}
class MathService {
    synchronized void getSumOfArray(int[] numbers) {
     int sum = 0;

         for (int number : numbers) {
             System.out.println(Thread.currentThread()
                     .getName()
                     + " adds "
                     + sum + " to "
                     + number + " to get -> "
                     + (sum += number));

             try {
                 Thread.sleep(500);
             } catch (InterruptedException e) {
                 throw new RuntimeException(e);
             }
         }
    }
}
public class Synchronization {
    public static void main(String[] args) {
        MathService mathService = new MathService();

        Thread threadOne = new Thread(() ->
                mathService.getSumOfArray(new int[]{10, 11, 12}));
        Thread threadTwo = new Thread(() ->
                mathService.getSumOfArray(new int[]{20, 21, 22}));

        threadOne.start();
        threadTwo.start();
    }
}

Vysvětlení kódu:

Spusťte tento příklad a všimněte si, že vlákno `0` nejprve získá zámek objektu `mathService` a používá výhradně tento zámek, dokud nedokončí provádění. Vlákno "0" a "1" není v tomto kódu proloženo. Výstup je zobrazen níže.

Výstup:

Thread-0 adds 0 to 10 to get -> 10
Thread-0 adds 10 to 11 to get -> 21
Thread-0 adds 21 to 12 to get -> 33
Thread-1 adds 0 to 20 to get -> 20
Thread-1 adds 20 to 21 to get -> 41
Thread-1 adds 41 to 22 to get -> 63

Použití synchronizovaného bloku

Předpokládejme, že nechcete synchronizovat celou metodu. Místo toho chcete synchronizovat několik řádků kódu. V té době, Synchronized block pomohl synchronizovat ten vybraný Java kód. SyncZámky hronized metody jsou přístupné na metodě, zatímco zámky synchronizovaných bloků jsou přístupné na objektu.

class MathService {
    void getSumOfArray(int[] numbers) {
        synchronized (this){
            int sum = 0;

            for (int number : numbers) {
                System.out.println(Thread.currentThread()
                        .getName()
                        + " adds "
                        + sum + " to "
                        + number + " to get -> "
                        + (sum += number));

                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
public class Synchronization {
    public static void main(String[] args) {
        MathService mathService = new MathService();

        Thread threadOne = new Thread(() ->
                mathService.getSumOfArray(new int[]{10, 11, 12}));
        Thread threadTwo = new Thread(() ->
                mathService.getSumOfArray(new int[]{20, 21, 22}));

        threadOne.start();
        threadTwo.start();
    }
}

Vysvětlení kódu:

Po spuštění tohoto kódu si všimnete, že funguje bez jakéhokoli rušení. V synchronizované metodě je zámek aplikován metodou, ale v synchronizovaném bloku je zámek aplikován objektem. Ujistěte se, že výstup odpovídá následujícímu obrázku.

Výstup:

Thread-0 adds 0 to 10 to get -> 10
Thread-0 adds 10 to 11 to get -> 21
Thread-0 adds 21 to 12 to get -> 33
Thread-1 adds 0 to 20 to get -> 20
Thread-1 adds 20 to 21 to get -> 41
Thread-1 adds 41 to 22 to get -> 63

Vysvětlení kódu:

Když tento kód spustíte, všimnete si, že funguje bez rušení, což jsme očekávali. V synchronizované metodě je zámek aplikován metodou, ale v metodě synchronizovaného bloku je zámek aplikován objektem.

Použití statické synchronizace

In Java synchronizace, pokud existuje více než jeden objekt, dvě vlákna mohou získat zámky a vstoupit do synchronizovaného bloku nebo bloku se samostatným zámkem pro každý objekt. Aby se tomu zabránilo, lze použít statickou synchronizaci. Syncpřed statickými metodami budou použita klíčová slova s ​​hronizovanou hodnotou.

Poznámka: Při statické synchronizaci je přístup k zámku na třídě, nikoli na objektu a metodě.

Kód pro demonstraci problému zamykání více objektů

class MathService {
    synchronized void getSumOfArray(int[] numbers) {
            int sum = 0;

            for (int number : numbers) {
                System.out.println(Thread.currentThread()
                        .getName()
                        + " adds "
                        + sum + " to "
                        + number + " to get -> "
                        + (sum += number));

                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
    }
}
public class Synchronization {
    public static void main(String[] args) {
        MathService mathService = new MathService();
        MathService mathService1 = new MathService();

        Thread threadOne = new Thread(() ->
                mathService.getSumOfArray(new int[]{10, 11, 12}));
        Thread threadTwo = new Thread(() ->
                mathService.getSumOfArray(new int[]{20, 21, 22}));
        Thread threadThree = new Thread(() ->
                mathService1.getSumOfArray(new int[]{10, 11, 12}));
        Thread threadFour = new Thread(() ->
                mathService1.getSumOfArray(new int[]{20, 21, 22}));

        threadOne.start();
        threadTwo.start();
        threadThree.start();
        threadFour.start();
    }
}

Vysvětlení kódu:

Když vytvoříme další instanci `MathService`, zavedeme interferenci ve vláknech, protože budou proložena dvěma objekty. Všimněte si, že vlákno `0` a vlákno `2` jsou prokládány těmito dvěma objekty, zatímco vlákna `1` a `3` jsou prokládány těmito dvěma objekty.

Výstup:

Thread-0 adds 0 to 10 to get -> 10
Thread-2 adds 0 to 10 to get -> 10
Thread-0 adds 10 to 11 to get -> 21
Thread-2 adds 10 to 11 to get -> 21
Thread-0 adds 21 to 12 to get -> 33
Thread-2 adds 21 to 12 to get -> 33
Thread-1 adds 0 to 20 to get -> 20
Thread-3 adds 0 to 20 to get -> 20
Thread-1 adds 20 to 21 to get -> 41
Thread-3 adds 20 to 21 to get -> 41
Thread-1 adds 41 to 22 to get -> 63
Thread-3 adds 41 to 22 to get -> 63

Stejný kód pomocí synchronizované statické metody

class MathService {
    synchronized static void getSumOfArray(int[] numbers) {
            int sum = 0;

            for (int number : numbers) {
                System.out.println(Thread.currentThread()
                        .getName()
                        + " adds "
                        + sum + " to "
                        + number + " to get -> "
                        + (sum += number));

                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
    }
}
public class Synchronization {
    public static void main(String[] args) {
        MathService mathService = new MathService();
        MathService mathService1 = new MathService();

        Thread threadOne = new Thread(() ->
                mathService.getSumOfArray(new int[]{10, 11, 12}));
        Thread threadTwo = new Thread(() ->
                mathService.getSumOfArray(new int[]{20, 21, 22}));
        Thread threadThree = new Thread(() ->
                mathService1.getSumOfArray(new int[]{10, 11, 12}));
        Thread threadFour = new Thread(() ->
                mathService1.getSumOfArray(new int[]{20, 21, 22}));

        threadOne.start();
        threadTwo.start();
        threadThree.start();
        threadFour.start();
    }
}

Spusťte výše uvedený kód a všimněte si, že jsme nyní odstranili interferenci vláken. Výstup kódu je uveden níže.

Výstup:

Thread-0 adds 0 to 10 to get -> 10
Thread-0 adds 10 to 11 to get -> 21
Thread-0 adds 21 to 12 to get -> 33
Thread-3 adds 0 to 20 to get -> 20
Thread-3 adds 20 to 21 to get -> 41
Thread-3 adds 41 to 22 to get -> 63
Thread-2 adds 0 to 10 to get -> 10
Thread-2 adds 10 to 11 to get -> 21
Thread-2 adds 21 to 12 to get -> 33
Thread-1 adds 0 to 20 to get -> 20
Thread-1 adds 20 to 21 to get -> 41
Thread-1 adds 41 to 22 to get -> 63

Výhody použití synchronizace

Zde jsou výhody při práci se souběžnými aplikacemi:

  • Hlavním cílem synchronizace v Java je zabránit nekonzistentním datům tím, že zabrání interferenci vláken.
  • Synchronizované klíčové slovo in Java poskytuje zamykání, které zajišťuje vzájemně se vylučující přístup ke sdílenému zdroji a zabraňuje závodům v datech.
  • Zabraňuje také změně pořadí příkazů kódu pomocí kompilátor, což může způsobit jemný souběžný problém, pokud nepoužíváme nestálá nebo synchronizovaná klíčová slova.
  • Syncklíčové slovo hronized čte data z hlavní paměti než z cache a když uvolní zámek.
  • Také vyprázdní operace zápisu z hlavní paměti, čímž eliminuje chyby nekonzistence paměti.

Nevýhody Synchronizační mechanismus

Syncronizační mechanismy mají špatný výkon.

Například

  • Předpokládejme, že existuje pět procesů, A1, A2, A3, A4 a A5.
  • Čekají, až sdílené prostředky přistupují k jednomu vláknu najednou.
  • Všechny procesy čekají, takže poslední ve frontě musí čekat, dokud nebudou dokončeny všechny ostatní procesy.

Shrnutí

  • Synchronizace označuje schopnost řídit přístup více vláken k libovolnému sdílenému prostředku.
  • Java má dva typy metod synchronizace: 1) Synchronizace procesů a 2) Synchronizace vláken.
  • Zavřít Java je postaven na vnitřní entitě známé jako monitor nebo zámek.
  • Vícevláknový program je metoda nebo blok chráněný před rušením z jiných vláken sdílejících stejný zdroj označený pomocí klíčového slova `synchronized`.
  • Každá metoda, která je deklarována jako synchronizovaná, je známá jako synchronizovaná metoda.
  • In Java, synchronizované zámky metod jsou přístupné na metodě, zatímco synchronizované blokové zámky jsou přístupné na objektu.
  • Při statické synchronizaci je přístup k zámku na třídě, nikoli na objektu a metodě.
  • Hlavním cílem synchronizace v Java je zabránit nekonzistentním datům tím, že zabrání interferenci vláken.
  • Největší nevýhodou této metody je, že všechny procesy čekají, takže poslední ve frontě musí čekat, dokud nebudou dokončeny všechny ostatní procesy.