Synchronizacja w Java

Co to jest Synchronizacja w Java?

In Java, synchronizacja odnosi się do możliwości kontrolowania dostępu wielu wątków do dowolnego współdzielonego zasobu. Jest to idealne rozwiązanie, gdy chcemy zezwolić tylko jednemu wątkowi na dostęp do współdzielonego zasobu.

To podejście do wykonywania jest zwykle określane jako programowanie `asynchroniczne`. Istnieją również wątki na tych procesorach, które są lekkimi procesami, które mogą wykonywać instrukcje jednocześnie.

Rodzaje Synchronizacja

Istnieją dwa rodzaje metod synchronizacji w Java:

1) Synchronizacja procesów

2) Synchronizacja wątków.

Przestudiujmy wątek i Synchronizacja procesów szczegółowo.

Synchronizacja procesów: Zarządza synchronizacją między programami. Na przykład programy takie jak `Microsoft Word` i `Acrobat reader` działają jako osobne procesy.

Synchronizacja wątków: Równoczesne wykonywanie zasobu krytycznego przez dwa lub więcej wątków nazywa się wątkiem Synchronizacja. Można dalej pogrupować w celu komunikacji wzajemnie wykluczającej się i międzywątkowej.

Co to jest Zablokuj Java?

Zamknij Java jest zbudowany wokół wewnętrznej jednostki zwanej monitorem lub zamkiem. Z każdym obiektem jest powiązany zamek. Zatem wątek wymagający stałego dostępu do pól obiektu musi uzyskać blokadę obiektu przed uzyskaniem do nich dostępu i zwolnić blokadę po zakończeniu pracy. Dzięki temu tylko jeden wątek będzie miał dostęp do udostępnionych danych w danym momencie.

Program wielowątkowy z synchronizacją

Program wielowątkowy jest metodą lub blokiem zabezpieczonym przed zakłóceniami ze strony innych wątków współdzielących ten sam zasób, wskazany za pomocą słowa kluczowego `synchronized`.

Korzystanie z metody synchronizowanej

Każda metoda, która jest zadeklarowana jako synchronized, jest znana jako synchronized Method. Jest ona również używana do blokowania obiektu dla dowolnego współdzielonego zasobu. Tak więc, gdy wątek wywołuje metodę synchronized, automatycznie przejmuje ona blokadę dla tego obiektu i zwalnia ją, gdy zakończy swoje zadanie.

Uwaga: Słowo kluczowe synchronized nie może działać z klasami i zmiennymi. Tylko metody i bloki mogą być używane ze słowem kluczowym.

Dlaczego warto korzystać z Synchronizowana metoda?

  • Służy do blokowania obiektu dla dowolnych współdzielonych zasobów.
  • Obiekt uzyskuje blokadę za każdym razem, gdy wywołana zostanie metoda synchronized.
  • Blokada nie zostanie zwolniona, dopóki gwint nie zakończy swojej funkcji

Składnia:

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();
    }
}

Wyjaśnienie kodu:

Uruchom ten przykład i zaobserwuj, że wątek `0` najpierw pobiera blokadę obiektu `mathService` i używa tej blokady wyłącznie do momentu zakończenia wykonywania. W tym kodzie wątki „0” i „1” nie są przeplatane. Dane wyjściowe są takie, jak pokazano poniżej.

Wyjście:

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

Korzystanie z bloku synchronizowanego

Załóżmy, że nie chcesz synchronizować całej metody. Zamiast tego chcesz zsynchronizować kilka linii kodu. W tym czasie Syncblok hronic pomógł zsynchronizować wybrane Java kod. SyncDostęp do blokad metod synchronicznych odbywa się na poziomie metody, natomiast dostęp do blokad bloków synchronicznych odbywa się na poziomie obiektu.

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();
    }
}

Wyjaśnienie kodu:

Po uruchomieniu tego kodu zauważysz, że działa on bez żadnych zakłóceń. W metodzie synchronized blokada jest stosowana przez metodę, ale w bloku synchronized blokada jest stosowana przez obiekt. Upewnij się, że dane wyjściowe są takie, jak pokazano poniżej.

Wyjście:

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

Wyjaśnienie kodu:

Gdy uruchomisz ten kod, zauważysz, że działa on bez zakłóceń, czego oczekiwaliśmy. W metodzie synchronized blokada jest stosowana przez metodę, ale w metodzie synchronized block blokada jest stosowana przez obiekt.

Korzystanie ze statycznej synchronizacji

In Java synchronizacja, jeśli jest więcej niż jeden obiekt, dwa wątki mogą nabyć blokady i wejść do zsynchronizowanego bloku lub bloku, z oddzielną blokadą dla każdego obiektu. Aby tego uniknąć, można użyć statycznej synchronizacji. Synchronizowane słowa kluczowe będą używane przed metodami statycznymi.

Uwaga: W przypadku synchronizacji statycznej dostęp do blokad jest możliwy na poziomie klasy, a nie obiektu i metody.

Kod demonstrujący problem blokowania wielu obiektów

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();
    }
}

Wyjaśnienie kodu:

Kiedy tworzymy kolejną instancję `MathService`, wprowadzamy interferencję w wątkach, ponieważ będą one przeplatane z dwoma obiektami. Zauważ, że wątki `0` i `2` są przeplatane z tymi dwoma obiektami, podczas gdy wątki `1` i `3` są przeplatane z tymi dwoma obiektami.

Wyjście:

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

Ten sam kod wykorzystujący metodę statyczną synchronizowaną

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();
    }
}

Uruchom powyższy kod i zauważ, że wyeliminowaliśmy teraz zakłócenia wątków. Wynik kodu pokazano poniżej.

Wyjście:

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

Zalety korzystania z synchronizacji

Oto zalety pracy z współbieżnymi aplikacjami:

  • Głównym celem synchronizacji w Java ma na celu zapobieganie niespójnym danym poprzez zapobieganie interferencji wątków.
  • Słowo kluczowe synchronized w Java zapewnia blokowanie, które gwarantuje wzajemnie wyłączny dostęp do współdzielonego zasobu i zapobiega wyścigowi danych.
  • Zapobiega także zmianie kolejności instrukcji kodu przez metodę kompilator, co może powodować subtelny problem, jeśli nie użyjemy słów kluczowych volatile lub synchronized.
  • Synchronized słowo kluczowe odczytuje dane z pamięci głównej niż z pamięci podręcznej i kiedy zwalnia blokadę.
  • Opróżnia również pamięć główną z operacji zapisu, eliminując błędy niespójności pamięci.

Wady SyncMechanizm ronizacji

SyncMechanizmy hronizacji mają słabą wydajność.

Na przykład

  • Załóżmy, że istnieje pięć procesów: A1, A2, A3, A4 i A5.
  • Czekają, aż udostępnione zasoby będą miały dostęp do jednego wątku na raz.
  • Wszystkie procesy oczekują, więc ostatni w kolejce musi poczekać, aż wszystkie inne procesy zostaną zakończone.

Podsumowanie

  • Synchronizacja odnosi się do możliwości kontrolowania dostępu wielu wątków do dowolnego współdzielonego zasobu.
  • Java ma dwa rodzaje metod synchronizacji: 1) Synchronizacja procesów i 2) Synchronizacja wątków.
  • Zamknij Java jest zbudowany wokół wewnętrznej jednostki zwanej monitorem lub zamkiem.
  • Program wielowątkowy to metoda lub blok zabezpieczony przed zakłóceniami ze strony innych wątków współdzielących ten sam zasób, wskazany za pomocą słowa kluczowego `synchronized`.
  • Każda metoda zadeklarowana jako synchronizowana jest nazywana metodą synchronizowaną.
  • In JavaDostęp do blokad metod synchronizowanych uzyskuje się na poziomie metody, natomiast dostęp do blokad bloków synchronizowanych uzyskuje się na poziomie obiektu.
  • W przypadku synchronizacji statycznej dostęp do blokad jest możliwy na poziomie klasy, a nie obiektu i metody.
  • Głównym celem synchronizacji w Java ma na celu zapobieganie niespójnym danym poprzez zapobieganie interferencji wątków.
  • Największą wadą tej metody jest to, że wszystkie procesy czekają, więc ostatni w kolejce musi poczekać, aż wszystkie inne procesy zostaną zakończone.