Что такое синхронизация в Java? метод, блок, статический тип

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

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

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

Типы синхронизации

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

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

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

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

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

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

Что такое блокировка в Java?

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

Многопоточная программа с синхронизацией

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

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

Любой метод, объявленный как синхронизированный, называется синхронизированным методом. Он также используется для блокировки объекта для любого общего ресурса. Итак, когда поток вызывает синхронизированный метод. Он автоматически захватывает блокировку этого объекта и снимает ее, когда завершает свою задачу.

Примечание: Ключевое слово синхронизировано не может работать с классами и переменными. С ключевым словом можно использовать только методы и блоки.

Зачем использовать синхронизированный метод?

  • Он используется для блокировки объекта для любых общих ресурсов.
  • Объект получает блокировку при каждом вызове синхронизированного метода.
  • Блокировка не снимается до тех пор, пока нить не выполнит свою функцию.

Синтаксис:

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

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

Предположим, вы не хотите синхронизировать весь метод. Вместо этого вы хотите синхронизировать несколько строк кода. В то время блок Synchronized помогал синхронизировать выбранный код Java.

Доступ к синхронизированным блокировкам метода осуществляется на методе, тогда как синхронизированные блокировки блоков доступны на объекте.

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

Расшифровка кода:

Когда вы запустите этот код, вы заметите, что он работает без помех, чего мы и ожидали. В синхронизированном методе блокировка применяется методом, но в синхронизированном блочном методе блокировка применяется объектом.

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

При синхронизации Java, если существует более одного объекта, два потока могут получить блокировки и войти в синхронизированный блок или блок с отдельной блокировкой для каждого объекта. Чтобы избежать этого, можно использовать статическую синхронизацию.

Синхронизированные ключевые слова будут использоваться перед статическими методами.

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

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

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

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

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

Например

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

Итоги

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