Syncхронизация в Java

Какво е Syncхронизация в Java?

In Java, синхронизирането се отнася до способността да се контролира достъпът на множество нишки до всеки споделен ресурс. Това е идеална опция, когато искаме да позволим само на една нишка да има достъп до споделения ресурс.

Този подход на изпълнение обикновено се нарича "асинхронно" програмиране. Има и нишки на тези процесори, които са леки процеси, които могат да изпълняват инструкции едновременно.

Видове Syncхронизация

Има два вида методи за синхронизация в Java:

1) Синхронизация на процеси

2) Синхронизиране на нишки.

Да учим Thread and Синхронизация на процеси подробно.

Процесна синхронизация: Управлява синхронизацията между програмите. Например програми като `Microsoft Word` и `Acrobat reader` се изпълняват като отделни процеси.

Синхронизиране на нишки: Едновременното изпълнение на критичния ресурс от две или повече нишки се нарича нишка Syncхронизация. Можете да бъдете групирани допълнително към взаимно изключващи се` и комуникация между нишки.

Какво е Lock in Java?

Заключвам Java е изграден около вътрешна единица, известна като монитор или ключалка. Всички обекти имат заключване, свързано с тях. И така, нишката, която се нуждае от последователен достъп до полетата на обект, трябва да получи заключването на обекта, преди да получи достъп до тях, и освобождава заключването, когато работата е свършена. Това гарантира, че само една нишка има достъп до споделените данни в даден момент.

Многонишкова програма със синхронизация

Многонишкова програма е метод или блок, защитен от намеса от други нишки, споделящи същия ресурс, посочен чрез ключовата дума `synchronized`.

Използване на синхронизирания метод

Всеки метод, който е деклариран като синхронизиран, е известен като синхронизиран метод. Използва се и за заключване на обект за всеки споделен ресурс. Така че, когато една нишка извиква синхронизиран метод. Той автоматично поема ключалката за този обект и го освобождава, когато приключи задачата си.

Забележка: Синхронизираната ключова дума не може да работи с класове и променливи. С ключовата дума могат да се използват само методи и блокове.

Защо да използвате Syncхронизиран метод?

  • Използва се за заключване на обект за всякакви споделени ресурси.
  • Обектът получава заключването при всяко извикване на синхронизирания метод.
  • Заключването не се освобождава, докато нишката не изпълни своята функция

Синтаксис:

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

Обяснение на кода:

Стартирайте този пример и наблюдавайте, че нишката `0` първо получава заключването на обекта `mathService` и използва изключително това заключване, докато не завърши изпълнението. Нишки `0` и `1` не се преплитат в този код. Резултатът е както е показано по-долу.

Изход:

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

Използване на синхронизиран блок

Да приемем, че не искате да синхронизирате целия метод. Вместо това искате да синхронизирате няколко реда код. По това време, Syncхронизираният блок помогна за синхронизирането на избрания Java код. Syncхронизираните заключвания на метода са достъпни на метода, докато синхронизираните заключвания на блокове са достъпни на обекта.

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

Обяснение на кода:

При стартиране на този код ще забележите, че работи без никакви смущения. При синхронизирания метод заключването се прилага от метода, но при синхронизирания блок заключването се прилага от обекта. Уверете се, че изходът е както е показано по-долу.

Изход:

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

Обяснение на кода:

Когато стартирате този код, ще забележите, че работи без смущения, което очаквахме. При синхронизирания метод заключването се прилага от метода, но при синхронизирания блоков метод заключването се прилага от обекта.

Използване на статична синхронизация

In Java синхронизация, ако има повече от един обект, две нишки могат да придобият ключалките и да влязат в синхронизиран блок или блок с отделна ключалка за всеки обект. За да се избегне това, може да се използва статична синхронизация. Syncхронизираните ключови думи ще се използват преди статичните методи.

Забележка: При статичната синхронизация заключващият достъп е за класа, а не за обекта и метода.

Код за демонстриране на проблема със заключването на множество обекти

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

Обяснение на кода:

Когато създаваме друг екземпляр на `MathService`, въвеждаме намеса в нишките, тъй като те ще бъдат вплетени с двата обекта. Обърнете внимание, че нишката `0` и нишката `2` се преплитат с двата обекта, докато нишките `1` и `3` се преплитат с двата обекта.

Изход:

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

Същият код, използващ синхронизиран статичен метод

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

Изпълнете горния код и отбележете, че вече сме елиминирали намесата в нишката. Резултатът от кода е показан по-долу.

Изход:

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

Предимства на използването на синхронизация

Ето предимствата при работа с едновременни приложения:

  • Основната цел на синхронизацията в Java е да предотврати непоследователни данни чрез предотвратяване на намеса в нишката.
  • Синхронизираната ключова дума в Java осигурява заключване, което гарантира взаимно изключващ се достъп до споделения ресурс и предотвратява надпреварата в данните.
  • Той също така предотвратява пренареждането на кодови изрази от компилатор, което може да причини фин паралелен проблем, ако не използваме променливи или синхронизирани ключови думи.
  • Synckronized ключова дума чете данни от основната памет, отколкото от кеша и когато освобождава заключването.
  • Той също така изчиства операциите за запис от основната памет, като елиминира грешките при несъответствие на паметта.

Недостатъци на SyncМеханизъм на хронизация

Syncхронизиране Механизмите имат лоша производителност.

Например

  • Да приемем, че има пет процеса, A1, A2, A3, A4 и A5.
  • Те чакат споделените ресурси за достъп до една нишка наведнъж.
  • Всички процеси остават в изчакване, така че последният в опашката трябва да изчака, докато всички останали процеси завършат.

Oбобщение

  • Syncхронизацията се отнася до способността да се контролира достъпът на множество нишки до всеки споделен ресурс.
  • Java има два типа методи за синхронизация: 1) Синхронизиране на процеси и 2) Синхронизиране на нишки.
  • Заключвам Java е изграден около вътрешна единица, известна като монитор или ключалка.
  • Многонишковата програма е метод или блок, защитен от намеса от други нишки, споделящи същия ресурс, посочен чрез ключовата дума `synchronized`.
  • Всеки метод, който е деклариран като синхронизиран, е известен като синхронизиран метод.
  • In Java, заключванията на синхронизираните методи се осъществяват в метода, докато заключванията на синхронизирани блокове се осъществяват в обекта.
  • При статичната синхронизация заключващият достъп е за класа, а не за обекта и метода.
  • Основната цел на синхронизацията в Java е да предотврати непоследователни данни чрез предотвратяване на намеса в нишката.
  • Най-големият недостатък на този метод е, че всички процеси се държат в изчакване, така че последният в опашката трябва да изчака, докато всички останали процеси завършат.