Java Threads

Оновлено: 22.05.2023

Потоки Java

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

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

Створення нитки

Існує два способи створення потоку.

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

public class Main extends Thread {
  public void run() {
    System.out.println("This code is running in a thread");

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

public class Main implements Runnable {
  public void run() {
    System.out.println("This code is running in a thread");
  }
}

Нитки, що біжать

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

public class Main extends Thread {
  public static void main(String[] args) {
    Main thread = new Main();
    thread.start();
    System.out.println("This code is outside of the thread");
  }
  public void run() {
    System.out.println("This code is running in a thread");
  }
}

Якщо клас реалізує інтерфейс 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("This code is outside of the thread");
  }
  public void run() {
    System.out.println("This code is running in a thread");
  }
}
Відмінності між "розширюючими" та "реалізуючими" потоками Основна відмінність полягає в тому, що коли клас розширює клас 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() для запобігання проблемам паралелізму:

isAlive()
public class Main extends Thread {
  public static int amount = 0;

  public static void main(String[] args) {
    Main thread = new Main();
    thread.start();
    // Wait for the thread to finish
    while(thread.isAlive()) {
    System.out.println("Waiting...");
// Update amount and print its value
  System.out.println("Main: " + amount);
  amount++;
  System.out.println("Main: " + amount);
public void run() {
    amount++;