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

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

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

Такой подход выполнения обычно называют «асинхронным» программированием. В этих процессорах также есть потоки — легкие процессы, которые могут выполнять инструкции одновременно.

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

Существует два типа методов синхронизации. Java:

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

2) Синхронизация потоков.

Давайте изучим Thread и Синхронизация процессов в деталях.

Синхронизация процессов: Он управляет синхронизацией между программами. Например, такие программы, как `Microsoft Word` и `Acrobat Reader` выполняются как отдельные процессы.

Синхронизация потоков: Одновременное выполнение критического ресурса двумя или более потоками называется потоком. Syncхронизация. Далее вас можно сгруппировать по взаимоисключающим и межпотоковым связям.

Что такое блокировка 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Ключевые слова hronized будут использоваться перед статическими методами.

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

Код, демонстрирующий проблему блокировки нескольких объектов

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 обеспечивает блокировку, которая гарантирует взаимоисключающий доступ к общему ресурсу и предотвращает гонку данных.
  • Это также предотвращает переупорядочение операторов кода компилятор, что может вызвать незначительную одновременную проблему, если мы не используем изменчивые или синхронизированные ключевые слова.
  • SyncКлючевое слово hronized считывает данные из основной памяти, а не из кэша, и когда оно снимает блокировку.
  • Он также сбрасывает операции записи из основной памяти, устраняя ошибки несогласованности памяти.

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

SyncМеханизмы хронизации имеют низкую производительность.

Например

  • Предположим, что имеется пять процессов: A1, A2, A3, A4 и A5.
  • Они ждут, пока общие ресурсы получат доступ к одному потоку за раз.
  • Все процессы находятся в режиме ожидания, поэтому последний в очереди должен дождаться завершения всех остальных процессов.

Резюме

  • SyncХронизация означает возможность контролировать доступ нескольких потоков к любому общему ресурсу.
  • Java имеет два типа методов синхронизации: 1) Синхронизация процессов и 2) Синхронизация потоков.
  • Блокировка в Java построен вокруг внутреннего объекта, известного как монитор или замок.
  • Многопоточная программа — это метод или блок, защищенный от вмешательства других потоков, использующих один и тот же ресурс, указанный с помощью ключевого слова «синхронизировано».
  • Любой метод, объявленный как синхронизированный, называется синхронизированным методом.
  • In Javaсинхронизированные блокировки методов осуществляются на уровне метода, тогда как синхронизированные блокировки блоков осуществляются на уровне объекта.
  • При статической синхронизации доступ к блокировке предоставляется классу, а не объекту и методу.
  • Основная цель синхронизации в Java заключается в предотвращении несогласованности данных путем предотвращения помех в потоках.
  • Самый большой недостаток этого метода заключается в том, что все процессы находятся в режиме ожидания, поэтому последний в очереди должен ждать завершения всех остальных процессов.