java synchronized what is thread synchronization java
Цей посібник пояснює синхронізацію потоків у Java, а також пов’язані з ним концепції, такі як блокування Java, стан перегонів, мутекс, нестабільність Java та безвихідність у Java:
У багатопотоковому середовищі, де задіяно кілька потоків, неодмінно виникають зіткнення, коли більше ніж один потік намагається отримати той самий ресурс одночасно. Результатом цих зіткнень є 'стан перегонів', і, отже, програма дає несподівані результати.
Наприклад, один файл оновлюється двома потоками. Якщо один потік T1 знаходиться в процесі оновлення цього файлу, скажіть якусь змінну. Зараз, поки це оновлення від T1 ще триває, припустимо, другий потік T2 також оновлює ту саму змінну. Таким чином змінна дасть неправильні результати.
=> Ознайомтесь із Повною серією навчання Java тут.
Коли задіяно декілька потоків, ми повинні керувати цими потоками таким чином, щоб доступ до ресурсу можна було отримати за один потік одночасно. У наведеному вище прикладі файлом, до якого отримують доступ обидва потоки, слід керувати таким чином, щоб T2 не мав доступу до файлу, поки T1 не закінчить доступ до нього.
Це робиться на Java за допомогою “ Синхронізація потоків '.
Що ви дізнаєтесь:
- Синхронізація потоків у Java
- Багатопоточність без синхронізації
- Багатопоточність із синхронізацією
- Висновок
Синхронізація потоків у Java
Оскільки Java є багатопотоковою мовою, синхронізація потоків має велике значення в Java, оскільки паралельно виконуються декілька потоків у програмі.
Ми використовуємо ключові слова “Синхронізовано” і “Мінливий” для досягнення синхронізації в Java
Нам потрібна синхронізація, коли спільний об’єкт або ресурс можна змінювати. Якщо ресурс незмінний, тоді потоки будуть читати ресурс лише одночасно або окремо.
У цьому випадку нам не потрібно синхронізувати ресурс. У цьому випадку JVM гарантує, що Синхронізований код Java виконується одним потоком за раз .
Здебільшого одночасний доступ до спільних ресурсів у Java може спричиняти такі помилки, як „Невідповідність пам’яті” та „Втручання потоків”. Щоб уникнути цих помилок, нам потрібно піти на синхронізацію спільних ресурсів, щоб доступ до цих ресурсів був взаємовиключним.
Ми використовуємо концепцію, яка називається Монітори для реалізації синхронізації. Одночасно доступ до монітора може мати лише один потік. Коли нитка отримує замок, ми можемо сказати, що нитка потрапила на монітор.
Коли доступ до монітора здійснюється за допомогою певного потоку, монітор блокується, а всі інші потоки, що намагаються увійти в монітор, призупиняються, поки доступний потік не закінчиться і не звільнить блокування.
Надалі ми детально обговоримо синхронізацію в Java у цьому підручнику. Тепер обговоримо деякі основні поняття, пов'язані з синхронізацією в Java.
Стан перегонів на Java
У багатопотоковому середовищі, коли більше ніж один потік намагається отримати доступ до спільного ресурсу для одночасного запису, тоді кілька потоків змагаються один з одним, щоб закінчити доступ до ресурсу. Це породжує „стан раси”.
Слід врахувати те, що немає проблем, якщо кілька потоків намагаються отримати доступ до спільного ресурсу лише для читання. Проблема виникає, коли кілька потоків одночасно отримують доступ до одного ресурсу.
Умови перегонів виникають через відсутність належної синхронізації потоків у програмі. Коли ми правильно синхронізуємо потоки таким чином, що одночасно лише один потік матиме доступ до ресурсу, і умова перегону перестане існувати.
То як ми можемо виявити стан перегонів?
Найкращий спосіб виявити стан перегонів - це перегляд коду. Як програмісту, ми повинні ретельно переглянути код, щоб перевірити наявність можливих умов перегонів.
Замки / монітори в Java
Ми вже згадували, що використовуємо монітори або блокування для здійснення синхронізації. Монітор або замок є внутрішньою сутністю і асоціюється з кожним об’єктом. Отже, коли потік потребує доступу до об’єкта, він повинен спочатку отримати замок або монітор свого об’єкта, попрацювати над об’єктом, а потім звільнити замок.
Замки в Java виглядатимуть так, як показано нижче:
public class Lock { private boolean isLocked = false; public synchronized void lock() throws InterruptedException { while(isLocked) { wait(); } isLocked = true; } public synchronized void unlock(){ isLocked = false; notify(); } }
Як показано вище, у нас є метод lock (), який блокує екземпляр. Усі потоки, що викликають метод lock (), будуть заблоковані, доки набори методів unblock () не будуть заблоковані як прапорець і повідомлятимуть усі потоки, що очікують.
Деякі вказівки, які слід пам’ятати про замки:
- У Java кожен об'єкт має замок або монітор. До цього замку можна отримати доступ за допомогою нитки.
- Одночасно лише один потік може придбати цей монітор або заблокувати.
- Мова програмування Java забезпечує ключове слово Synchronized, яке дозволяє нам синхронізувати потоки, роблячи блок або метод як Synchronized.
- Спільні ресурси, до яких потрібно отримати доступ потокам, зберігаються під цим синхронізованим блоком / методом.
Мьютекси в Java
Ми вже обговорювали, що в багатопотоковому середовищі можуть виникати умови гонки, коли більше ніж один потік намагається одночасно отримати доступ до спільних ресурсів, а умови гонки призводять до несподіваних результатів.
Частина програми, яка намагається отримати доступ до спільного ресурсу, називається “Критичний розділ” . Щоб уникнути виникнення перегонових умов, потрібно синхронізувати доступ до критичної секції. Синхронізуючи цей критичний розділ, ми переконуємось, що одночасно доступ до критичного розділу може мати лише один потік.
Найпростішим типом синхронізатора є “mutex”. Mutex гарантує, що в кожному конкретному випадку лише один потік може виконати критичний розділ.
Мьютекс схожий на концепцію моніторів або замків, яку ми обговорювали вище. Якщо потоку потрібно отримати доступ до критичного розділу, тоді він повинен отримати мьютекс. Після того, як мутекс отриманий, потік отримає доступ до критичного коду розділу, а після закінчення звільнить мутекс.
Інші потоки, які чекають доступу до критичного розділу, тим часом будуть заблоковані. Як тільки потік, що утримує мьютекс, звільняє його, інший потік увійде до критичного розділу.
DVD для копіювання та запису програмного забезпечення безкоштовно
Є кілька способів, за допомогою яких ми можемо реалізувати мьютекс в Java.
- Використання синхронізованого ключового слова
- Використання семафору
- Використання ReentrantLock
У цьому підручнику ми обговоримо перший підхід, тобто синхронізацію. Інші два підходи - Semaphore та ReentrantLock будуть розглянуті в наступному уроці, де ми обговоримо паралельний пакет Java.
Синхронізоване ключове слово
Java надає ключове слово «Синхронізовано», яке можна використовувати в програмі для позначення критичного розділу. Критичним розділом може бути блок коду або повний метод. Таким чином, лише один потік може отримати доступ до критичного розділу, позначеного ключовим словом Synchronized.
Ми можемо написати паралельні частини (частини, які виконуються одночасно) для програми, використовуючи ключове слово Synchronized. Ми також позбавляємось від умов перегонів, створюючи блок коду або метод Synchronized.
Коли ми позначаємо блок або метод синхронізованими, ми захищаємо спільні ресурси всередині цих об’єктів від одночасного доступу та, тим самим, пошкодження.
Типи синхронізації
Існує 2 типи синхронізації, як описано нижче:
# 1) Синхронізація процесу
Синхронізація процесів передбачає одночасне виконання кількох процесів або потоків. Зрештою вони досягають стану, коли ці процеси або потоки здійснюють певну послідовність дій.
# 2) Синхронізація ниток
У Thread Synchronization більше одного потоку намагається отримати доступ до спільного простору. Потоки синхронізуються таким чином, що спільний простір одночасно отримує доступ лише до одного потоку.
Синхронізація процесів виходить за рамки цього посібника. Отже, ми будемо тут обговорювати лише Синхронізацію ниток.
У Java ми можемо використовувати синхронізоване ключове слово з:
- Блок коду
- Метод
Вищезазначені типи є взаємовиключними типами потокової синхронізації. Взаємне виключення заважає потокам, що отримують доступ до спільних даних, перешкоджати один одному.
Іншим типом синхронізації потоків є “InterThread комунікація”, яка базується на співпраці між потоками. Зв'язок між нитками виходить за рамки цього посібника.
Перш ніж продовжувати синхронізацію блоків та методів, давайте реалізуємо програму Java, щоб продемонструвати поведінку потоків, коли синхронізація відсутня.
Багатопоточність без синхронізації
Наступна програма Java має кілька потоків, які не синхронізовані.
class PrintCount { //method to print the thread counter public void printcounter() { try { for(int i = 5; i > 0; i--) { System.out.println('Counter ==> ' + i ); } } catch (Exception e) { System.out.println('Thread interrupted.'); } } } //thread class class ThreadCounter extends Thread { private Thread t; private String threadName; PrintCount PD; //class constructor for initialization ThreadCounter( String name, PrintCount pd) { threadName = name; PD = pd; } //run method for thread public void run() { PD.printcounter(); System.out.println('Thread ' + threadName + ' exiting.'); } //start method for thread public void start () { System.out.println('Starting ' + threadName ); if (t == null) { t = new Thread (this, threadName); t.start (); } } } public class Main { public static void main(String args()) { PrintCount PD = new PrintCount(); //create two instances of thread class ThreadCounter T1 = new ThreadCounter( 'ThreadCounter_1 ', PD ); ThreadCounter T2 = new ThreadCounter( 'ThreadCounter_2 ', PD ); //start both the threads T1.start(); T2.start(); // wait for threads to end try { T1.join(); T2.join(); } catch ( Exception e) { System.out.println('Interrupted'); } } }
Вихідні дані
З вихідних даних ми бачимо, що оскільки потоки не синхронізовані, вихід є суперечливим. Обидва потоки починаються, а потім вони відображають лічильник один за одним. Обидві нитки виходять в кінці.
З даної програми перший потік повинен був вийти після відображення значень лічильника, а потім другий потік повинен був почати відображати значення лічильника.
Тепер перейдемо до синхронізації та почнемо з синхронізації блоку коду.
Блок синхронізованого коду
Синхронізований блок використовується для синхронізації блоку коду. Цей блок зазвичай складається з декількох рядків. Синхронізований блок використовується, коли ми не хочемо, щоб синхронізувався весь метод.
Наприклад, у нас є метод, скажімо, з 75 рядків коду. З цього лише 10 рядків коду потрібно виконувати одним потоком за раз. У цьому випадку, якщо ми зробимо весь метод синхронізованим, це буде тягарем для системи. У таких ситуаціях ми використовуємо синхронізовані блоки.
Обсяг синхронізованого методу завжди менший, ніж обсяг синхронізованого методу. Синхронізований метод блокує об’єкт спільного ресурсу, який повинен використовуватися кількома потоками.
Загальний синтаксис синхронізованого блоку наведений нижче:
synchronized (lock_object){ //synchronized code statements }
Тут “lock_object” є виразним посиланням на об’єкт, за яким слід отримати замок. Отже, коли потік хоче отримати доступ до синхронізованих операторів всередині блоку для виконання, тоді він повинен отримати блокування на моніторі ‘lock_object’.
Як уже обговорювалося, синхронізоване ключове слово гарантує, що лише один потік може отримувати блокування за раз, а всі інші потоки повинні чекати, поки потік, що утримує замок, закінчується і звільняє замок.
Примітка
- 'NullPointerException' викидається, якщо для lock_object використовується значення Null.
- Якщо нитка спить, утримуючи замок, замок не відпускається. Інші потоки не матимуть доступу до спільного об’єкта протягом цього часу сну.
Зараз ми представимо наведений вище приклад, який вже був реалізований з невеликими змінами. У попередній програмі ми не синхронізували код. Тепер ми використаємо синхронізований блок і порівняємо вихідні дані.
Багатопоточність із синхронізацією
У наведеній нижче програмі Java ми використовуємо синхронізований блок. У методі запуску ми синхронізуємо код рядків, які друкують лічильник для кожного потоку.
class PrintCount { //print thread counter public void printCounter() { try { for(int i = 5; i > 0; i--) { System.out.println('Counter ==> ' + i ); } } catch (Exception e) { System.out.println('Thread interrupted.'); } } } //thread class class ThreadCounter extends Thread { private Thread t; private String threadName; PrintCount PD; //class constructor for initialization ThreadCounter( String name, PrintCount pd) { threadName = name; PD = pd; } //run () method for thread with synchronized block public void run() { synchronized(PD) { PD.printCounter(); } System.out.println('Thread ' + threadName + ' exiting.'); } //start () method for thread public void start () { System.out.println('Starting ' + threadName ); if (t == null) { t = new Thread (this, threadName); t.start (); } } } public class Main { public static void main(String args()) { PrintCount PD = new PrintCount(); //create thread instances ThreadCounter T1 = new ThreadCounter( 'Thread_1 ', PD ); ThreadCounter T2 = new ThreadCounter( 'Thread_2 ', PD ); //start both the threads T1.start(); T2.start(); // wait for threads to end try { T1.join(); T2.join(); } catch ( Exception e) { System.out.println('Interrupted'); } } }
Вихідні дані
Зараз вихід цієї програми з використанням синхронізованого блоку є досить послідовним. Як і очікувалося, обидва потоки починають виконуватися. Перший потік закінчив відображати значення лічильника та виходи. Потім другий потік відображає значення лічильника і виходить.
Синхронізований метод
Давайте обговоримо синхронізований метод у цьому розділі. Раніше ми вже бачили, що ми можемо оголосити невеликий блок, що складається з меншої кількості рядків коду, як синхронізований блок. Якщо ми хочемо, щоб вся функція була синхронізована, тоді ми можемо оголосити метод синхронізованим.
Коли метод синхронізується, тоді лише один потік зможе одночасно здійснювати виклик методу.
Загальним синтаксисом для написання синхронізованого методу є:
synchronized method_name (parameters){ //synchronized code }
Як і синхронізований блок, у випадку синхронізованого методу нам потрібен lock_object, який буде використовуватися потоками, що отримують доступ до синхронізованого методу.
Для синхронізованого методу об’єкт блокування може бути одним із наступних:
- Якщо синхронізований метод є статичним, тоді об’єкт блокування надається об’єктом ‘.class’.
- Для нестатичного методу об’єкт блокування задається поточним об’єктом, тобто ‘цим’ об’єктом.
Особливістю синхронізованого ключового слова є те, що воно знову входить. Це означає, що синхронізований метод може викликати інший синхронізований метод із тим самим блокуванням. Отже, нитка, що утримує замок, може отримати доступ до іншого синхронізованого методу без необхідності отримувати інший замок.
Синхронізований метод продемонстровано на наведеному нижче прикладі.
де я можу дивитись аніме в Інтернеті
class NumberClass { //synchronized method to print squares of numbers synchronized void printSquares(int n) throws InterruptedException { //iterate from 1 to given number and print the squares at each iteration for (int i = 1; i <= n; i++) { System.out.println(Thread.currentThread().getName() + ' :: '+ i*i); Thread.sleep(500); } } } public class Main { public static void main(String args()) { final NumberClass number = new NumberClass(); //create thread Runnable thread = new Runnable() { public void run() { try { number.printSquares(3); } catch (InterruptedException e) { e.printStackTrace(); } } }; //start thread instance new Thread(thread, 'Thread One').start(); new Thread(thread, 'Thread Two').start(); } }
Вихідні дані
У наведеній вище програмі ми використовували синхронізований метод для друку квадратів числа. Верхня межа числа передається методу як аргумент. Потім, починаючи з 1, квадрати кожного числа друкуються до досягнення верхньої межі.
В основній функції створюється екземпляр потоку. Кожному екземпляру потоку передається число для друку квадратів.
Як згадувалося вище, коли метод, що підлягає синхронізації, є статичним, тоді об’єкт блокування бере участь у класі, а не об’єкт. Це означає, що ми будемо фіксувати клас, а не об’єкт. Це називається статичною синхронізацією.
Інший приклад наведено нижче.
class Table{ //synchronized static method to print squares of numbers synchronized static void printTable(int n){ for(int i=1;i<=10;i++){ System.out.print(n*i + ' '); try{ Thread.sleep(400); }catch(Exception e){} } System.out.println(); } } //thread class Thread_One class Thread_One extends Thread{ public void run(){ Table.printTable(2); } } //thread class Thread_Two class Thread_Two extends Thread{ public void run(){ Table.printTable(5); } } public class Main{ public static void main(String t()){ //create instances of Thread_One and Thread_Two Thread_One t1=new Thread_One (); Thread_Two t2=new Thread_Two (); //start each thread instance t1.start(); t2.start(); } }
Вихідні дані
У наведеній вище програмі ми друкуємо таблиці множення чисел. Кожне число, таблиця якого буде надруковано, є екземпляром потоку іншого класу потоку. Таким чином, ми друкуємо таблиці множення 2 і 5, тому у нас є два класи thread_one і thread_two для друку таблиць 2 і 5 відповідно.
Підводячи підсумок, синхронізоване ключове слово Java виконує такі функції:
- Синхронізоване ключове слово в Java гарантує взаємовиключний доступ до спільних ресурсів, забезпечуючи механізм блокування. Блокування також запобігає перегоновим умовам.
- Використовуючи синхронізоване ключове слово, ми запобігаємо одночасним помилкам програмування в коді.
- Коли метод або блок оголошено як синхронізовані, тоді потоку потрібна ексклюзивна блокування, щоб увійти до синхронізованого методу або блоку. Після виконання необхідних дій потік звільняє замок і виконує операцію запису. Таким чином він усуне помилки пам’яті, пов’язані з непослідовністю.
Нестабільна в Java
Нестабільне ключове слово в Java використовується для того, щоб зробити класи безпечними для потоків. Ми також використовуємо ключове слово volatile для зміни значення змінної різними потоками. Нестабільне ключове слово можна використовувати для оголошення змінної як з примітивними типами, так і з об’єктами.
У деяких випадках летюче ключове слово використовується як альтернатива синхронізованому ключовому слову, але зауважте, що воно не замінює синхронізоване ключове слово.
Коли змінна оголошується нестабільною, її значення ніколи не кешується, а завжди зчитується з основної пам'яті. Нестабільна змінна гарантує впорядкування та видимість. Хоча змінну можна оголосити мінливою, ми не можемо оголосити класи або методи мінливими.
Розглянемо наступний блок коду:
class ABC{ static volatile int myvar =10; }
У наведеному вище коді змінна myvar є статичною та мінливою. Статична змінна є спільною для всіх об'єктів класу. Енергозмінна змінна завжди знаходиться в основній пам’яті і ніколи не кешується.
Отже, в основній пам'яті буде лише одна копія myvar, і всі дії з читання / запису будуть виконуватися з цією змінною з основної пам'яті. Якби myvar не було оголошено мінливим, тоді кожен об'єкт потоку мав би іншу копію, що призвело б до невідповідностей.
Деякі відмінності між нестабільними та синхронізованими ключовими словами перелічені нижче.
Нестабільне ключове слово | Синхронізоване ключове слово |
---|---|
Ключове слово volatile використовується лише зі змінними. | Синхронізоване ключове слово використовується з блоками коду та методами. |
Нестабільне ключове слово не може заблокувати потік очікування. | Синхронізоване ключове слово може заблокувати потік очікування. |
Продуктивність ниток покращується завдяки Volatile. | Продуктивність потоків дещо погіршується при синхронізації. |
Нестійкі змінні знаходяться в основній пам'яті. | Синхронізовані конструкції не містяться в основній пам'яті. |
Енергонезалежна синхронізує одну змінну між потоковою пам’яттю та основною пам’яттю за раз. | Синхронізоване ключове слово синхронізує всі змінні одночасно. |
Тупик в Java
Ми побачили, що ми можемо синхронізувати декілька потоків за допомогою синхронізованого ключового слова і зробити програми безпечними для потоків. Синхронізуючи потоки, ми гарантуємо, що кілька потоків виконуються одночасно в багатопотоковому середовищі.
Однак іноді трапляється ситуація, коли потоки більше не можуть функціонувати одночасно. Натомість вони чекають нескінченно. Це відбувається, коли один потік очікує на ресурс, а цей ресурс заблокований другим потоком.
Натомість другий потік чекає на ресурсі, який заблокований першим потоком. Така ситуація породжує “тупик” на Java.
Тупикова ситуація в Java зображена на зображенні нижче.
Як ми бачимо з наведеної схеми, потік A заблокував ресурс r1 і чекає ресурс r2. Поток B, навпаки, заблокував ресурс r2 і чекає на r1.
Таким чином, жоден з потоків не може закінчити своє виконання, якщо не зачепить очікувані ресурси. Ця ситуація призвела до глухого кута, коли обидва потоки нескінченно чекають ресурсів.
Нижче наведено приклад тупикових ситуацій в Java.
public class Main { public static void main(String() args) { //define shared resources final String shared_res1 = 'Java tutorials'; final String shared_res2 = 'Multithreading'; // thread_one => locks shared_res1 then shared_res2 Thread thread_one = new Thread() { public void run() { synchronized (shared_res1) { System.out.println('Thread one: locked shared resource 1'); try { Thread.sleep(100);} catch (Exception e) {} synchronized (shared_res2) { System.out.println('Thread one: locked shared resource 2'); } } } }; // thread_two=> locks shared_res2 then shared_res1 Thread thread_two = new Thread() { public void run() { synchronized (shared_res2) { System.out.println('Thread two: locked shared resource 2'); try { Thread.sleep(100);} catch (Exception e) {} synchronized (shared_res1) { System.out.println('Thread two: locked shared resource 1'); } } } }; //start both the threads thread_one.start(); thread_two.start(); } }
Вихідні дані
У наведеній вище програмі ми маємо два спільні ресурси та два потоки. Обидва потоки намагаються отримати доступ до спільних ресурсів по одному. Вихідні дані показують, що обидва потоки блокують по одному ресурсу в очікуванні інших. Тим самим створюється тупикова ситуація.
Незважаючи на те, що ми не можемо повністю зупинити тупикові ситуації, ми, безумовно, можемо уникнути їх, виконавши певні кроки.
Нижче перераховані засоби, за допомогою яких ми можемо уникнути тупикових ситуацій у Java.
# 1) Уникаючи вкладених замків
Наявність вкладених замків - найважливіша причина виникнення тупикових ситуацій. Вкладені замки - це замки, які надаються декільком потокам. Таким чином, нам слід уникати надання замків більше ніж одній нитці.
# 2) Використовуйте нитку Join
Ми повинні використовувати Thread.join з максимальним часом, щоб потоки могли використовувати максимальний час для виконання. Це запобіжить тупиковий стан, який здебільшого виникає, оскільки одна нитка постійно чекає інших.
# 3) Уникайте зайвого блокування
Ми повинні заблокувати лише необхідний код. Наявність непотрібних блокувань для коду може призвести до тупикових ситуацій у програмі. Оскільки тупикові ситуації можуть зламати код і перешкоджати потоку програми, ми повинні бути схильними уникати тупикових ситуацій у наших програмах.
Часті запитання
Q # 1) Що таке синхронізація і чому вона важлива?
Відповідь: Синхронізація - це процес контролю доступу спільного ресурсу до декількох потоків. Без синхронізації кілька потоків можуть одночасно оновлювати або змінювати спільний ресурс, що призводить до невідповідностей.
Таким чином, ми повинні забезпечити, щоб у багатопотоковому середовищі потоки синхронізувались, щоб спосіб доступу до спільних ресурсів був взаємовиключним та послідовним.
Q # 2) Що таке синхронізація та несинхронізація в Java?
Відповідь: Синхронізація означає, що конструкція є безпечною для потоків. Це означає, що кілька потоків не можуть отримати доступ до конструкції (блок коду, метод тощо) одночасно.
Несинхронізовані конструкції не є безпечними для потоків. Кілька потоків можуть отримати доступ до несинхронізованих методів або блоків у будь-який час. Популярним несинхронізованим класом в Java є StringBuilder.
Q # 3) Чому потрібна синхронізація?
Відповідь: Коли процеси повинні виконуватися одночасно, нам потрібна синхронізація. Це тому, що нам потрібні ресурси, якими можна розподіляти багато процесів.
Щоб уникнути зіткнень між процесами або потоками для доступу до спільних ресурсів, нам потрібно синхронізувати ці ресурси, щоб усі потоки отримали доступ до ресурсів, а програма також працювала безперебійно.
Q # 4) Як отримати синхронізований ArrayList?
Відповідь: Ми можемо використовувати метод Collections.synchronized list з ArrayList як аргумент для перетворення ArrayList в синхронізований список.
Q # 5) Чи синхронізована HashMap?
Запитання та відповіді на співбесіду з HTML5 для досвідчених pdf
Відповідь: Ні, HashMap не синхронізується, але HashTable синхронізується.
Висновок
У цьому підручнику ми детально обговорили Синхронізацію потоків. Разом з цим ми також дізналися про нестабільне ключове слово та глухих кутів у Java. Синхронізація складається з синхронізації процесів і потоків.
У багатопотоковому середовищі ми більше стурбовані синхронізацією потоків. Тут ми бачили підхід синхронізованого ключового слова до синхронізації потоків.
Тупик - це ситуація, коли кілька потоків нескінченно чекають ресурсів. Ми бачили приклад тупикових ситуацій у Java разом із методами уникнення тупикових ситуацій у Java.
=> Завітайте сюди, щоб вивчити Java з нуля.
Рекомендована література
- Thread.Sleep () - метод Thread Sleep () у Java із прикладами
- Потоки Java з методами та життєвим циклом
- Основи Java: Синтаксис Java, клас Java та основні концепції Java
- Багатопотоковість на Java - Підручник із прикладами
- Багатопотоковість на C ++ з прикладами
- Підручник JAVA для початківців: 100+ практичних відео-підручників Java
- Компоненти Java: платформа Java, JDK, JRE та віртуальна машина Java
- Підручник із рядків Java | Рядові методи Java на прикладах