Засоби мови Java для роботи з потоками виконання. Клас Thread. Інтерфейс Runnable. Головний потік виконання. Створення дочірнього потоку
Зміст
- 1. Способи створення потоків виконання
- 2. Клас Thread. Конструктори. Огляд методів
- 3. Інтерфейс Runnable. Особливості застосування
- 4. Головний потік виконання. Особливості. Доступ до головного потоку виконання
- 5. Приклад, що демонструє доступ до головного потоку виконання
- 6. Приклад, що демонструє створення дочірнього потоку шляхом реалізації інтерфейсу Runnable
- 7. Приклад, що демонструє створення дочірнього потоку шляхом розширення класу Thread
- Зв’язані теми
Пошук на інших ресурсах:
1. Способи створення потоків виконання
У мові Java потік виконання можна створювати одним з двох способів:
- шляхом розширення класу Thread. Цей клас є основним класом, на якому побудована багатопотокова система Java. Клас Thread визначає один потік виконання. Якщо в програмі потрібно створити три потоки виконання, то, відповідно, створюється три екземпляри класу Thread;
- з допомогою реалізації інтерфейсу Runnable. Інтерфейс Runnable доповнює можливості класу Thread
⇑
2. Клас Thread. Конструктори. Огляд методів
Клас Thread є основним класом при роботі з потоками виконання. Створення будь-якого потоку починається зі створення екземпляру класу Thread. При цьому можна використовувати наступні конструктори класу
Thread(Runnable threadObject) Thread(Runnable threadObject, String threadName)
тут
- threadObject – об’єкт деякого класу, який потрібно виконати у потоці. Цей об’єкт повинен реалізовувати інтерфейс Runnable (дивіться нижче) або розширювати клас Thread;
- threadName – ім’я, яке встановлюється для новоствореного потоку виконання. Це ім’я може бути прочитане методом getName().
В загальному випадку, код створення потоку виконання з іменем “My thread” для об’єкту класу MyThreadClass виглядає наступним чином:
... // Створити екземпляр класу MyThreadClass MyThreadClass threadObject = new MyThreadClass(); // Створити дочірній потік у головному потоці Thread thr = new Thread(threadObject, "My thread"); ...
Клас Thread містить ряд методів для роботи з потоками виконання. Нижче наведено опис цих методів у класі:
- getName() – отримати ім’я потоку виконання;
- getPriority() – отримати пріоритет потоку виконання;
- isAlive() – визначити, чи виконується потік;
- join() – призначений для очікування завершення потоку виконання;
- run() – задає код, який повинен виконуватись у потоці виконання. Це є точка входу в потік;
- sleep() – призупиняє виконання викликаючого потоку виконання на заданий час;
- start() – запускає потік виконання з допомогою виклику методу run().
Приклади використання вищенаведених методів можна вивчити тут і тут.
⇑
3. Інтерфейс Runnable. Особливості застосування
Інтерфейс Runnable використовується для створення потоку виконання. Потік виконання можна створити з об’єкту класу, який реалізує інтерфейс Runnable.
Інтерфейс оголошує один метод run(), який має наступну загальну форму:
public abstract void run();
Методом run() визначається точка входу в потік. Як тільки завершиться виконання методу run(), завершиться і виконання потоку. У методі run() можна виконувати будь-які операції, що притаманні звичайним методам (оголошувати змінні, використовувати класи, викликати інші методи тощо).
В загальному випадку, створення потоку виконання для класу MyThreadClass виглядає наступним чином:
class MyThreadClass implements Runnable { // ... public void run() { // Програмний код, що виконується в потоці // ... } }
⇑
4. Головний потік виконання. Особливості. Доступ до головного потоку виконання
Після запуску на виконання програми на мові Java, починає виконуватись один потік – головний потік програми. Для головного потоку можна виділити такі характерні особливості:
- головний потік починає виконуватись першим;
- з головного потоку можна породити (створити) усі дочірні потоки;
- бажано, щоб головний потік завершувався останнім, і виконував деякі завершальні дії при закритті програми.
Щоб отримати доступ до головного потоку виконання, потрібно створити екземпляр класу Thread з допомогою виклику статичного методу currentThread(). Після цього, з допомогою екземпляру, можна використовувати додаткові функції керування головним потоком (призупинити головний потік, отримати інформацію про головний потік, тощо).
⇑
5. Приклад, що демонструє доступ до головного потоку виконання
У прикладі продемонстровано доступ до головного потоку в програмі та його використання.
public class TrainThreads { public static void main(String[] args) { // Отримати дані про головний потік виконання // 1. Отримати об'єкт головного потоку Thread thr = Thread.currentThread(); // 2. Вивести дані про поточний потік виконання System.out.println("Current thread: " + thr); // 3. Встановити нове ім'я потоку виконання thr.setName("MY THREAD"); // 4. Повторно вивести дані про потік виконання System.out.println("Current thread: " + thr); // 5. Продемонструвати роботу потоку виконання try { for (int n=5; n>0; n--) { System.out.println(n); Thread.sleep(1000); // зупинити виконання потоку на 1 секунду } } catch (InterruptedException e) { System.out.println("The main thread is interrupted."); } } }
Результат роботи програми
Current thread: Thread[main,5,main] Current thread: Thread[MY THREAD,5,main] 5 4 3 2 1
⇑
6. Приклад, що демонструє створення дочірнього потоку шляхом реалізації інтерфейсу Runnable
Одним зі способів створення дочірнього потоку є реалізація інтерфейсу Runnable. Якщо клас використовує інтерфейс Runnable, то в цьому класі потрібно реалізовувати метод run().
// Приклад створення потоку з допомогою реалізації інтерфейсу Runnable. // В інтерфейсі Runnable визначено метод run(), який потрібно реалізувати. class MyThread implements Runnable { Thread thr; // посилання на поточний потік виконання // Конструктор класу. У конструкторі потрібно створити потік MyThread() { // створити новий потік thr = new Thread(this, "Thread: MyThread"); System.out.println("Дочірній потік створено."); thr.start(); // запустити потік } // Реалізація методу run() з інтерфейсу Runnable public void run() { try { for (int i=10; i>0; i--) { System.out.println("Дочірній потік: " + i); Thread.sleep(500); } } catch (InterruptedException e) { System.out.println("Дочірній потік перервано."); } System.out.println("Дочірній потік завершено."); } } public class TrainThreads { public static void main(String[] args) { // Демонстрація роботи дочірнього потоку new MyThread(); // створити новий потік try { for (int i=10; i>0; i--) { System.out.println("Головний потік: " + i); Thread.sleep(1000); } } catch (InterruptedException e) { System.out.println("Головний потік перервано."); } System.out.println("Головний потік завершено."); } }
Результат виконання програми
Дочірній потік створено. Головний потік: 10 Дочірній потік: 10 Дочірній потік: 9 Головний потік: 9 Дочірній потік: 8 Дочірній потік: 7 Дочірній потік: 6 Головний потік: 8 Дочірній потік: 5 Головний потік: 7 Дочірній потік: 4 Дочірній потік: 3 Головний потік: 6 Дочірній потік: 2 Дочірній потік: 1 Головний потік: 5 Дочірній потік завершено. Головний потік: 4 Головний потік: 3 Головний потік: 2 Головний потік: 1 Головний потік завершено.
⇑
7. Приклад, що демонструє створення дочірнього потоку шляхом розширення класу Thread
Інший спосіб створення потоку – успадкування (розширення) класу Thread. При цьому способі є доступні деякі методи суперкласу Thread. Більш детально про використання методів класу Thread описується тут.
// Створення дочірнього потоку з допомогою розширення класу Thread class MyThread extends Thread { // Конструктор public MyThread() { // створити новий потік виконання super("Демонстраційний потік"); System.out.println("Дочірній потік."); start(); } // Реалізація власного методу run(), у цьому методі // вказуються дії (робота), які виконує наш потік public void run() { try { for (int i=10; i>0; i--) { System.out.println("Дочірній потік: " + i); Thread.sleep(500); } } catch (InterruptedException e) { System.out.println("Дочірній потік перервано."); } System.out.println("Дочірній потік завершено."); } } public class TrainThreads { public static void main(String[] args) { // Демонстрація створення потоку new MyThread(); // створити дочірній потік try { for (int i=10; i>0; i--) { System.out.println("Головний потік: " + i); Thread.sleep(1000); } } catch (InterruptedException e) { System.out.println("Головний потік перервано:"); } System.out.println("Головний потік завершено."); } }
Результат виконання програми
Дочірній потік створено. Дочірній потік: 10 Головний потік: 10 Дочірній потік: 9 Головний потік: 9 Дочірній потік: 8 Дочірній потік: 7 Дочірній потік: 6 Головний потік: 8 Дочірній потік: 5 Дочірній потік: 4 Головний потік: 7 Дочірній потік: 3 Дочірній потік: 2 Головний потік: 6 Дочірній потік: 1 Головний потік: 5 Дочірній потік завершено. Головний потік: 4 Головний потік: 3 Головний потік: 2 Головний потік: 1 Головний потік завершено.
⇑
Зв’язані теми
- Багатозадачність. Потоки виконання. Основні поняття
- Методи класу Thread: getName(), run(), start(), sleep(). Приклади
- Методи класу Thread: join(), isAlive(), getPriority(), setPriority(). Приклади
- Приклади розв’язку задач на потоки виконання (Threads). Робота з файлами в потоках. Сортування в потоках
⇑