Syncхронізація в Java
Що таке Syncхронізація в Java?
In Java, синхронізація означає можливість контролювати доступ кількох потоків до будь-якого спільного ресурсу. Це ідеальний варіант, коли ми хочемо дозволити лише одному потоку отримати доступ до спільного ресурсу.
Такий підхід до виконання зазвичай називають «асинхронним» програмуванням. На цих процесорах також є потоки, які є легкими процесами, які можуть виконувати інструкції одночасно.
Види Syncхронізація
Існує два типи методів синхронізації Java:
1) Синхронізація процесів
2) Синхронізація потоків.
Вивчаємо Thread і Синхронізація процесів детально.
Синхронізація процесів: Він керує синхронізацією між програмами. Наприклад, такі програми, як `Microsoft Word` і `Acrobat reader` запускаються як окремі процеси.
Синхронізація потоків: Одночасне виконання критичного ресурсу двома або більше потоками називається потоком Syncхронізація. Ви можете бути згруповані до взаємовиключних і міжпотокових комунікацій.
Що таке Lock in Java?
Зафіксувати Java будується навколо внутрішньої сутності, відомої як монітор або замок. Усі об’єкти мають пов’язані з ними замки. Таким чином, потік, якому потрібен узгоджений доступ до полів об’єкта, повинен отримати блокування об’єкта перед тим, як отримати доступ до них, і він знімає блокування, коли робота буде виконана. Це забезпечує одночасний доступ до спільних даних лише одному потоку.
Багатопотокова програма з синхронізацією
Багатопотокова програма це метод або блок, захищений від втручання з боку інших потоків, які спільно використовують той самий ресурс, що вказується за допомогою ключового слова `synchronized`.
Використання синхронізованого методу
Будь-який метод, оголошений як синхронізований, називається синхронізованим методом. Він також використовується для блокування об'єкта для будь-якого спільного ресурсу. Отже, коли потік викликає синхронізований метод. Він автоматично блокує цей об’єкт і звільняє його, коли завершить своє завдання.
Примітка: Ключове слово 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 забезпечує блокування, яке забезпечує взаємовиключний доступ до спільного ресурсу та запобігає гонці даних.
- Це також запобігає зміні порядку операторів коду компілятор, що може спричинити незначну одночасну проблему, якщо ми не використовуємо змінні або синхронізовані ключові слова.
- SyncКлючове слово hronized зчитує дані з основної пам'яті, ніж з кешу, і коли воно знімає блокування.
- Він також очищає операції запису з основної пам’яті, усуваючи помилки невідповідності пам’яті.
Недоліки SyncМеханізм хронізації
SyncМеханізми хронізації мають низьку продуктивність.
Наприклад
- Припустимо, що існує п’ять процесів: A1, A2, A3, A4 і A5.
- Вони чекають, поки спільні ресурси отримають доступ до одного потоку за раз.
- Усі процеси залишаються в режимі очікування, тому останній у черзі повинен чекати, поки не завершаться всі інші процеси.
Підсумки
- SyncХронізація відноситься до здатності контролювати доступ кількох потоків до будь-якого спільного ресурсу.
- Java має два типи методів синхронізації: 1) Синхронізація процесів і 2) Синхронізація потоків.
- Зафіксувати Java будується навколо внутрішньої сутності, відомої як монітор або замок.
- Багатопотокова програма — це метод або блок, захищений від втручання з боку інших потоків, які спільно використовують той самий ресурс, що вказується за допомогою ключового слова `synchronized`.
- Будь-який метод, який оголошено як синхронізований, називається синхронізованим методом.
- In Javaдоступ до синхронізованих блокувань методів здійснюється в методі, тоді як доступ до блокувань синхронізованих блоків здійснюється в об’єкті.
- У статичній синхронізації доступ до блокування надається класу, а не об’єкту та методу.
- Основна мета синхронізації в Java полягає в тому, щоб запобігти неузгодженим даним шляхом запобігання перешкод потоку.
- Найбільшим недоліком цього методу є те, що всі процеси залишаються в режимі очікування, тому останній у черзі повинен чекати, поки не завершаться всі інші процеси.