Java — Потоки

Потоки в Java

Потоки дозволяють програмі працювати ефективніше, виконуючи кілька завдань одночасно.

Потоки можна використовувати для виконання складних завдань у фоновому режимі без переривання основної програми.

Створення потоку

Є два способи створити потік.

Потік можна створити, розширивши клас Thread та переозначивши його метод run():

public class Main extends Thread {  
 public void run() {  
 System.out.println("Цей код виконується в потоці");  
 }  
}

Інший спосіб створити потік — реалізувати інтерфейс Runnable:

public class Main implements Runnable {  
 public void run() {  
 System.out.println("Цей код виконується в потоці");  
 }  
}

Запуск потоків

Якщо клас розширює клас Thread, потік можна запустити, створивши екземпляр класу та викликавши його метод start():

public class Main extends Thread {  
 public static void main(String[] args) {  
 Main thread = new Main();  
 thread.start();  
 System.out.println("Цей код знаходиться поза потоком");  
 }  
 public void run() {  
 System.out.println("Цей код виконується в потоці");  
 }  
}

Якщо клас реалізує інтерфейс Runnable, потік можна запустити, передавши екземпляр класу в конструктор об'єкта Thread, а потім викликавши метод start() потоку:

public class Main implements Runnable {  
 public static void main(String[] args) {  
 Main obj = new Main();  
 Thread thread = new Thread(obj);  
 thread.start();  
 System.out.println("Цей код знаходиться поза потоком");  
 }  
 public void run() {  
 System.out.println("Цей код виконується в потоці");  
 }  
}

Різниця між "розширенням" і "реалізацією" потоків

Основна різниця полягає в тому, що коли клас розширює клас Thread, ви не можете розширювати інший клас, але реалізуючи інтерфейс Runnable, можна також розширювати інший клас, наприклад: клас MyClass extends OtherClass implements Runnable.

Проблеми з паралельністю

Оскільки потоки виконуються одночасно з іншими частинами програми, немає способу визначити, в якому порядку буде виконуватися код. Коли потоки та основна програма читають і записують одні й ті ж змінні, значення можуть бути непередбачуваними. Проблеми, що виникають через це, називаються проблемами з паралельністю.

Приклад коду, де значення змінної amount є непередбачуваним:

public class Main extends Thread {  
 public static int amount = 0;  
 public static void main(String[] args) {  
 Main thread = new Main();  
 thread.start();  
 System.out.println(amount);  
 amount++;  
 System.out.println(amount);  
 }  
 public void run() {  
 amount++;  
 }  
}

Щоб уникнути проблем з паралельністю, найкраще ділити якомога менше атрибутів між потоками. Якщо атрибути потрібно ділити, одним із можливих рішень є використання методу isAlive() потоку для перевірки, чи завершив потік виконання, перед тим як використовувати будь-які атрибути, які потік може змінювати.

Використовуйте isAlive() для запобігання проблемам з паралельністю:

public class Main extends Thread {  
 public static int amount = 0;  
 public static void main(String[] args) {  
 Main thread = new Main();  
 thread.start();  
 // Чекаємо, поки потік завершиться  
 while(thread.isAlive()) {  
 System.out.println("Чекаю...");  
 }  
 // Оновлюємо amount і виводимо його значення  
 System.out.println("Main: " + amount);  
 amount++;  
 System.out.println("Main: " + amount);  
 }  
 public void run() {  
 amount++;  
 }  
}




Перекладено з: [Java — Threads](https://medium.com/@sithilasomaratne2010/java-threads-b10ef8aaf971)

Leave a Reply

Your email address will not be published. Required fields are marked *