Багатопотоковість в Java
Будь-яка програма може мати кілька процесів (примірників). Кожному з цих процесів можна призначити один або декілька потоків. У цьому посібнику ми побачимо, як виконувати кілька завдань одночасно, а також дізнаємося більше про потоки та синхронізацію між потоками.
Що таке Single Thread?
Одна нитка в Java в основному є легкою та найменшою одиницею обробки. Java використовує потоки за допомогою «класу потоку». Існує два типи ниток – потік користувача та потік демона (потоки daemon використовуються, коли ми хочемо очистити програму, і використовуються у фоновому режимі). Коли програма вперше запускається, створюється потік користувача. Опублікувавши це, ми можемо створити багато потоків користувачів і потоків демонів.
Приклад одного потоку:
package demotest;
public class GuruThread
{
public static void main(String[] args) {
System.out.println("Single Thread");
}
}
Переваги однієї нитки:
- Зменшує накладні витрати в програмі, оскільки в системі виконується один потік
- Крім того, це зменшує витрати на обслуговування програми.
Що таке багатопотоковість Java?
Багатопотоковість in Java це процес виконання двох або більше потоків одночасно для максимального використання ЦП. Багатопотокові програми виконують два або більше потоків, що виконуються одночасно. Тому він також відомий як Concurrency in Java. Кожна нитка йде паралельно одна одній. Кілька потоків не виділяють окрему область пам’яті, тому вони економлять пам’ять. Крім того, перемикання контексту між потоками займає менше часу.
Приклад багатопоточності:
package demotest;
public class GuruThread1 implements Runnable
{
public static void main(String[] args) {
Thread guruThread1 = new Thread("Guru1");
Thread guruThread2 = new Thread("Guru2");
guruThread1.start();
guruThread2.start();
System.out.println("Thread names are following:");
System.out.println(guruThread1.getName());
System.out.println(guruThread2.getName());
}
@Override
public void run() {
}
}
Переваги багатопоточності:
- Користувачі не блокуються, оскільки потоки незалежні, і ми можемо одночасно виконувати кілька операцій
- Таким чином, потоки є незалежними, інші потоки не постраждають, якщо один потік зустріне виняток.
Життєвий цикл потоку в Java
Життєвий цикл потоку:

Існують різні етапи життєвого циклу потоку, як показано на схемі вище:
- Нові
- Біговий
- Робота
- Очікування
- померлі
- Нове: На цьому етапі потік створюється за допомогою класу Thread class. Він залишається в цьому стані до програми починається нитка. Він також відомий як уроджена нитка.
- Запуск: На цій сторінці екземпляр потоку викликається за допомогою методу start. Керування потоком передається планувальнику для завершення виконання. Від планувальника залежить, чи запускати потік.
- Запуск: Коли потік починає виконуватися, стан змінюється на стан «виконується». Планувальник вибирає один потік із пулу потоків, і він починає виконуватися в програмі.
- Очікування: Це стан, коли потік має чекати. Оскільки в програмі працює кілька потоків, існує потреба в синхронізації між потоками. Отже, один потік повинен чекати, поки не буде виконано інший потік. Тому цей стан називають станом очікування.
- Мертві: Це стан, коли потік завершується. Потік знаходиться в стані виконання, і як тільки він завершив обробку, він перебуває в «мертвому стані».
Методи багатопоточності в Java
Нижче наведено деякі з поширених методів для потоків:| Метод | Опис |
|---|---|
| start () | Цей метод запускає виконання потоку і JVM викликає метод run() у потоці. |
| Сон (цілі мілісекунди) | Цей метод робить потік сплячим, отже, виконання потоку буде призупинено на мілісекунди, надані, а після цього потік знову почне виконуватися. Це допомагає синхронізувати потоки. |
| getName () | Він повертає назву потоку. |
| setPriority(int newpriority) | Це змінює пріоритет потоку. |
| вихід () | Це призводить до зупинки поточного потоку та виконання інших потоків. |
приклад: У цій багатопотоковій програмі в Java Наприклад, ми збираємося створити потік і досліджувати вбудовані методи, доступні для потоків.
package demotest;
public class thread_example1 implements Runnable {
@Override
public void run() {
}
public static void main(String[] args) {
Thread guruthread1 = new Thread();
guruthread1.start();
try {
guruthread1.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
guruthread1.setPriority(1);
int gurupriority = guruthread1.getPriority();
System.out.println(gurupriority);
System.out.println("Thread Running");
}
}
Пояснення коду:
- Code Лінія 2: Ми створюємо клас “thread_Example1”, який реалізує інтерфейс Runnable (він має бути реалізований будь-яким класом, екземпляри якого призначені для виконання потоком).
- Code Лінія 4: Він перевизначає метод запуску виконуваного інтерфейсу, оскільки перевизначення цього методу є обов’язковим
- Code Лінія 6: Тут ми визначили основний метод, у якому ми почнемо виконання потоку.
- Code Лінія 7: Тут ми створюємо нову назву потоку як «guruthread1», створюючи новий клас потоку.
- Code Лінія 8: ми будемо використовувати метод «запуск» потоку, використовуючи екземпляр «guruthread1». Тут потік почне виконуватися.
- Code Лінія 10: Тут ми використовуємо метод «сплячого» потоку з використанням екземпляра «guruthread1». Таким чином, потік буде спати протягом 1000 мілісекунд.
- Code 9-14: Тут ми помістили метод сну в блок try catch, оскільки виникає перевірена виняткова ситуація, тобто перервана виняткова ситуація.
- Code Лінія 15: Тут ми встановлюємо пріоритет потоку на 1 незалежно від того, який пріоритет він був
- Code Лінія 16: Тут ми отримуємо пріоритет потоку за допомогою getPriority()
- Code Лінія 17: Тут ми друкуємо значення, отримане з getPriority
- Code Лінія 18: Тут ми пишемо текст, який виконується.
Коли ви виконуєте наведений вище код, ви отримуєте такий результат:
вихід:
5 — це пріоритет Thread, а Thread Running — це текст, який є результатом нашого коду.
Java Нитка Syncхронізація
У багатопоточності існує асинхронна поведінка програм. Якщо один потік записує деякі дані, а інший потік одночасно читає дані, це може створити неузгодженість у програмі. Коли є потреба отримати доступ до спільних ресурсів через два або більше потоків, тоді використовується підхід синхронізації. Java надав синхронізовані методи для реалізації синхронізованої поведінки.
У цьому підході, як тільки потік потрапляє всередину синхронізованого блоку, жоден інший потік не може викликати цей метод для того самого об’єкта. Усі потоки повинні чекати, поки цей потік завершить синхронізований блок і вийде з нього. Таким чином, синхронізація допомагає в багатопоточних програмах. Один потік повинен чекати, поки інший потік завершить своє виконання, тільки тоді інші потоки можуть виконуватися.
Його можна записати в такій формі:
Synchronized(object)
{
//Block of statements to be synchronized
}
Багатопотоковість в Java Приклади програм
При цьому багатопотоковість Java наприклад, ми візьмемо два потоки та отримаємо імена потоку.
Example1:
GuruThread1.java
package demotest;
public class GuruThread1 implements Runnable{
/**
* @param args
*/
public static void main(String[] args) {
Thread guruThread1 = new Thread("Guru1");
Thread guruThread2 = new Thread("Guru2");
guruThread1.start();
guruThread2.start();
System.out.println("Thread names are following:");
System.out.println(guruThread1.getName());
System.out.println(guruThread2.getName());
}
@Override
public void run() {
}
}
Пояснення коду:
- Code Лінія 3: Ми відвідали заняття «Guru«Thread1», який реалізує Runnable (його має реалізувати будь-який клас, екземпляри якого призначені для виконання потоком).
- Code Лінія 8: Це основний метод класу
- Code Лінія 9: Тут ми створюємо екземпляр класу Thread і створюємо екземпляр під назвою «guruThread1» і створюємо потік.
- Code Лінія 10: Тут ми створюємо екземпляр класу Thread і створюємо екземпляр під назвою «guruThread2» і створюємо потік.
- Code Лінія 11: Ми починаємо тему, тобто guruThread1.
- Code Лінія 12: Ми починаємо тему, тобто guruThread2.
- Code Лінія 13: Виведення тексту у вигляді «Назви потоків такі:»
- Code Лінія 14: Отримання імені потоку 1 за допомогою методу getName() класу потоку.
- Code Лінія 15: Отримання імені потоку 2 за допомогою методу getName() класу потоку.
Коли ви виконуєте наведений вище код, ви отримуєте такий результат:
вихід:
Назви потоків виводяться тут як
- Guru1
- Guru2
Приклад 2:
У цій багатопоточності в Java Наприклад, ми дізнаємося про перевизначення методів run() і start() інтерфейсу, що виконується, і створимо два потоки цього класу та запустимо їх відповідно.
Крім того, ми відвідуємо два класи,
- Такий, який реалізовуватиме запущений інтерфейс і
- Ще один, який матиме основний метод і виконуватиметься відповідно.
package demotest;
public class GuruThread2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
GuruThread3 threadguru1 = new GuruThread3("guru1");
threadguru1.start();
GuruThread3 threadguru2 = new GuruThread3("guru2");
threadguru2.start();
}
}
class GuruThread3 implements Runnable {
Thread guruthread;
private String guruname;
GuruThread3(String name) {
guruname = name;
}
@Override
public void run() {
System.out.println("Thread running" + guruname);
for (int i = 0; i < 4; i++) {
System.out.println(i);
System.out.println(guruname);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("Thread has been interrupted");
}
}
}
public void start() {
System.out.println("Thread started");
if (guruthread == null) {
guruthread = new Thread(this, guruname);
guruthread.start();
}
}
}
Пояснення коду:
- Code Лінія 2: Ось ми відвідуємо заняття "Guru«Потік2», який міститиме метод main.
- Code Лінія 4: Тут ми беремо головний метод класу.
- Code Рядок 6-7: Тут ми створюємо екземпляр класу GuruThread3 (який створено в наведених нижче рядках коду) як “threadguru1”, і ми починаємо цей потік.
- Code Рядок 8-9: Тут ми створюємо ще один екземпляр класу GuruThread3 (який створено в наведених нижче рядках коду) як “threadguru2”, і ми починаємо цей потік.
- Code Лінія 11: Тут ми створюємо клас «Guru«Thread3», який реалізує інтерфейс runnable (він має бути реалізований будь-яким класом, екземпляри якого призначені для виконання потоком).
- Code Рядок 13-14: ми беремо дві змінні класу, одна з яких відноситься до класу потоків, а інша - до класу рядків.
- Code Рядок 15-18: ми переосмислюємо GuruКонструктор Thread3, який приймає один аргумент як рядковий тип (тобто назву потоку), що присвоюється змінній класу guruname, і таким чином зберігається назва потоку.
- Code Лінія 20: Тут ми перевизначаємо метод run() інтерфейсу, що виконується.
- Code Лінія 21: Ми виводимо назву потоку за допомогою оператора println.
- Code Рядок 22-31: Тут ми використовуємо цикл for з лічильником, ініціалізованим рівним 0, і він не повинен бути меншим за 4 (ми можемо взяти будь-яке число, отже, тут цикл виконуватиметься 4 рази) і збільшуємо лічильник. Ми друкуємо назву потоку, а також переводимо його в сплячий режим на 1000 мілісекунд у блоці try-catch, оскільки метод сну викликав перевірене виключення.
- Code Лінія 33: Тут ми перевизначаємо метод запуску запущеного інтерфейсу.
- Code Лінія 35: Виводимо текст «Thread started».
- Code Рядок 36-40: Тут ми використовуємо умову if, щоб перевірити, чи має змінна класу guruthread значення чи ні. Якщо значення null, ми створюємо екземпляр за допомогою класу потоку, який приймає ім’я як параметр (значення для якого було призначено в конструкторі). Після цього потік запускається за допомогою методу start().
Коли ви виконуєте наведений вище код, ви отримуєте такий результат:
Вихід:
Є два потоки, отже, ми отримуємо два рази повідомлення «Потік розпочато».
Ми отримуємо назви потоку, як ми їх вивели.
Він переходить у цикл for, де ми друкуємо лічильник і назву потоку, а лічильник починається з 0.
Цикл виконується тричі, а між ними потік перебуває в режимі сну на 1000 мілісекунд.
Отже, спочатку ми отримуємо guru1, потім guru2, потім знову guru2, тому що потік тут спить протягом 1000 мілісекунд, а потім наступний guru1 і знову guru1, потік спить протягом 1000 мілісекунд, тому ми отримуємо guru2, а потім guru1.
Резюме
У цьому підручнику ми бачили багатопотокові програми Java і як використовувати один і багато потоків у Java.
- Поясніть багатопотоковість в Java: у багатопоточності користувачі не блокуються, оскільки потоки є незалежними та можуть виконувати декілька операцій одночасно
- Різні етапи життєвого циклу потоку:
- Нові
- Біговий
- Робота
- Очікування
- померлі
- Ми також дізналися про синхронізація між потоками, що сприяє безперебійній роботі програми.
- Багатопотокове програмування в Java полегшує виконання багатьох інших прикладних завдань.



