— Привіт, Аміго! Ти вже знаєш дещо про потоки. У цій лекції будемо розбиратися з тим, як з ними працювати. Щоб створити новий потік потрібно:

1) Створити об'єкт класу Thread (потік)

2) Передати в нього об'єкт, метод якого потрібно виконати

3) Викликати у створеного об'єкта Thread метод start.

Приклад:

Код Опис
class Printer implements Runnable
{
public void run()
{
System.out.println("I’m printer");
}
}
Клас, який реалізує інтерфейс Runnable.
public static void main(String[] args)
{
Printer printer = new Printer();
Thread childThread = new Thread(printer);
childThread.start();
}
1 Створили об'єкт класу Printer, який містить метод run.
2 Створили новий об'єкт класу Thread, передали йому в конструкторі об'єкт printer, чий метод run() потрібно буде виконати.
3 Запустили новий потік у роботу за допомогою виклику методу start().

Маленькі програми на Java зазвичай складаються з одного потоку, який називається «головним потоком» (main thread). Але більші програми частіше запускають додаткові потоки, їх ще називають «дочірніми потоками». Головний потік виконує метод main та завершується. Аналогом такого методу main для дочірніх потоків служить метод run інтерфейсу Runnable.

— Ага, багато потоків, багато методів main.

— Щоб вказати, з якого методу потрібно почати виконання об'єкта Thread, необхідно якось передати метод цьому об'єкту. У Java це реалізовано за допомогою Runnable. Цей інтерфейс містить єдиний абстрактний метод – void run(). Клас Thread має конструктор Thread(Runnable runnable), до якого можна передати будь-який об'єкт, що реалізує інтерфейс Runnable.

Ти повинен успадкувати свій клас від інтерфейсу Runnable, потім перевизначити метод run у своєму класі. Саме з виклику цього методу почнеться робота нового потоку. У методі run ти можеш написати все, що хочеш.

Код Опис
class Printer implements Runnable
{
private String name;
public Printer(String name)
{
this.name = name;
}
public void run()
{
System.out.println("I’m " + this.name);
}
}
Клас, який реалізує інтерфейс Runnable.
public static void main(String[] args)
{
Printer printer1 = new Printer("Микола");
Thread thread1 = new Thread(printer1);
thread1.start();

Printer printer2 = new Printer("Василь");
Thread thread2 = new Thread(printer2);
thread2.start();
}
Створюємо два потоки, кожен на основі свого об'єкта типу Printer.
public static void main(String[] args)
{
Printer printer = new Printer("Наталя");

Thread thread1 = new Thread(printer);
thread1.start();

Thread thread2 = new Thread(printer);
thread2.start();

Thread thread3 = new Thread(printer);
thread3.start();
}
Створюємо три потоки на основі одного об'єкта Printer.

Більше того, можна поєднати це все в одному класі. Клас Thread успадкувався від інтерфейсу Runnable, і достатньо просто перевизначити його метод run:

Другий спосіб створення нового потоку
class Printer extends Thread
{
private String name;
public Printer(String name)
{
this.name = name;
}
public void run()
{
System.out.println("I’m " + this.name);
}
}
Успадкувались від класу Thread, який реалізує інтерфейс Runnable, і перевизначили метод run.
public static void main(String[] args)
{
Printer printer = new Printer("Василь");
printer.start();

Printer printer2 = new Printer("Микола");
printer2.start();

}
Створюємо два потоки, кожен на основі свого об'єкта типу Printer.

— Це рішення гарніше.

— Так, але в нього є мінуси:

1) Вам може знадобитися запустити кілька потоків на основі лише одного об'єкта, як це зроблено в «прикладі з Наталкою».

2) Якщо ви успадкувалися від класу Thread, ви не можете додати ще один батьківський клас до свого класу.

3) Якщо ваш клас має батьківський клас, ви не можете додати інший – Thread.

— Тобто кожен з потоків після виклику методу start почне виконувати метод run того об'єкта, який передали йому в конструкторі?

— Так. А якщо в конструкторі нічого не передали, Thread просто виконує свій внутрішній метод run.

— А чому не можна просто викликати цей метод, наприклад:

Код
public static void main(String[] args)
{
 Printer printer1 = new Printer("Микола");
 printer1.run();
}

— Коли головний потік дійде до методу run, наш «маленький робот» просто зайде всередину і почне виконувати всі команди, які є всередині, і лише після їхнього виконання повернеться в метод main і продовжить роботу далі. Створення другого «маленького робота» не відбудеться, і вся робота робитиметься послідовно, а не паралельно (одночасно).

— Зрозуміло. А чи можна викликати якийсь інший метод, а не run?

— Ні. Все прив'язано до інтерфейсу Runnable, а він «знає» лише один свій метод – run.