Учебники по Java

Ява ГЛАВНАЯ Введение в Java Начало работы с Java Синтаксис Java Java-комментарии Java-переменные Типы данных Java Приведение типов Java Операторы Java Java-строки Java-математика Логические значения Java Java, если...иначе Java-переключатель Java-цикл во время выполнения Java для цикла Перерыв/продолжение Java Массивы Java

Java-методы

Java-методы Параметры метода Java Перегрузка метода Java Область применения Java Java-рекурсия

Java-классы

Java ООП Классы/объекты Java Атрибуты класса Java Методы класса Java Конструкторы Java Модификаторы Java Инкапсуляция Java Java-пакеты/API Наследование Java Java-полиморфизм Внутренние классы Java Java-абстракция Java-интерфейс Перечисления Java Пользовательский ввод Java Дата Java Список массивов Java Связанный список Java Java HashMap Набор хэшей для Java Java-итератор Классы-оболочки Java Исключения Java Java регулярное выражение Java-потоки Java-лямбда

Обработка файлов Java

Java-файлы Создание/запись файлов Java Файлы чтения Java Java Удалить файлы

Java Как

Добавить два числа

Справочник по Java

Ключевые слова Java Строковые методы Java Java математические методы

Примеры Java

Примеры Java Компилятор Java Java-упражнения Java-викторина Java-сертификат


Java -потоки


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, можно расширить и другой класс, например: class MyClass extends OtherClass implements Runnable.


Проблемы параллелизма

Поскольку потоки выполняются одновременно с другими частями программы, невозможно узнать, в каком порядке будет выполняться код. Когда потоки и основная программа читают и записывают одни и те же переменные, значения становятся непредсказуемыми. Возникающие в результате проблемы называются проблемами параллелизма.

Пример

Пример кода, где значение переменной суммы непредсказуемо:

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();
    // 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++;
  }
}