Учебники

Java Concurrency — Обзор

Java — это многопоточный язык программирования, что означает, что мы можем разрабатывать многопоточные программы с использованием Java. Многопоточная программа содержит две или более частей, которые могут работать одновременно, и каждая из них может одновременно выполнять разные задачи, оптимально используя доступные ресурсы, особенно если на вашем компьютере установлено несколько процессоров.

По определению многозадачность — это когда несколько процессов совместно используют общие ресурсы обработки, такие как ЦП. Многопоточность расширяет идею многозадачности в приложениях, где вы можете разделить определенные операции в рамках одного приложения на отдельные потоки. Каждый из потоков может работать параллельно. ОС делит время обработки не только между различными приложениями, но и между каждым потоком в приложении.

Многопоточность позволяет вам писать так, чтобы несколько действий могли выполняться одновременно в одной и той же программе.

Жизненный цикл потока

Нить проходит через различные стадии своего жизненного цикла. Например, поток рождается, запускается, запускается, а затем умирает. Следующая диаграмма показывает полный жизненный цикл потока.

Нить Java

Ниже приведены этапы жизненного цикла —

  • Новый — новый поток начинает свой жизненный цикл в новом состоянии. Он остается в этом состоянии, пока программа не запустит поток. Это также упоминается как прирожденная нить .

  • Runnable — после запуска только что созданного потока поток становится работоспособным. Поток в этом состоянии считается выполняющим свою задачу.

  • Ожидание — иногда поток переходит в состояние ожидания, пока поток ожидает, пока другой поток выполнит задачу. Поток возвращается в состояние выполнения только тогда, когда другой поток сигнализирует ожидающему потоку о продолжении выполнения.

  • Временное ожидание — работающий поток может войти в состояние ожидания по времени в течение определенного интервала времени. Поток в этом состоянии возвращается в работоспособное состояние, когда истекает этот временной интервал или когда происходит ожидаемое событие.

  • Завершено (Dead) — работающий поток входит в завершенное состояние, когда он завершает свою задачу или иным образом завершает свою работу.

Новый — новый поток начинает свой жизненный цикл в новом состоянии. Он остается в этом состоянии, пока программа не запустит поток. Это также упоминается как прирожденная нить .

Runnable — после запуска только что созданного потока поток становится работоспособным. Поток в этом состоянии считается выполняющим свою задачу.

Ожидание — иногда поток переходит в состояние ожидания, пока поток ожидает, пока другой поток выполнит задачу. Поток возвращается в состояние выполнения только тогда, когда другой поток сигнализирует ожидающему потоку о продолжении выполнения.

Временное ожидание — работающий поток может войти в состояние ожидания по времени в течение определенного интервала времени. Поток в этом состоянии возвращается в работоспособное состояние, когда истекает этот временной интервал или когда происходит ожидаемое событие.

Завершено (Dead) — работающий поток входит в завершенное состояние, когда он завершает свою задачу или иным образом завершает свою работу.

Приоритеты потоков

Каждый поток Java имеет приоритет, который помогает операционной системе определять порядок, в котором запланированы потоки.

Приоритеты потоков Java находятся в диапазоне между MIN_PRIORITY (константа 1) и MAX_PRIORITY (константа 10). По умолчанию каждому потоку присваивается приоритет NORM_PRIORITY (константа 5).

Потоки с более высоким приоритетом более важны для программы и должны выделять процессорное время перед потоками с более низким приоритетом. Однако приоритеты потоков не могут гарантировать порядок выполнения потоков и очень сильно зависят от платформы.

Создайте поток, реализуя работающий интерфейс

Если ваш класс предназначен для выполнения в виде потока, вы можете добиться этого, реализуя интерфейс Runnable . Вам нужно будет выполнить три основных шага —

Шаг 1

В качестве первого шага вам необходимо реализовать метод run (), предоставляемый интерфейсом Runnable . Этот метод обеспечивает точку входа для потока, и вы поместите всю свою бизнес-логику в этот метод. Ниже приведен простой синтаксис метода run ():

public void run( )

Шаг 2

На втором этапе вы создадите экземпляр объекта Thread, используя следующий конструктор:

Thread(Runnable threadObj, String threadName);

Где threadObj — это экземпляр класса, который реализует интерфейс Runnable, а threadName — это имя, данное новому потоку.

Шаг 3

Как только объект Thread создан, вы можете запустить его, вызвав метод start () , который выполняет вызов метода run (). Ниже приведен простой синтаксис метода start ():

void start();

пример

Вот пример, который создает новый поток и запускает его:

Live Demo

class RunnableDemo implements Runnable {
   private Thread t;
   private String threadName;

   RunnableDemo(String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }
   
   public void run() {
      System.out.println("Running " +  threadName );
      
      try {
      
         for(int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);
            
            // Let the thread sleep for a while.
            Thread.sleep(50);
         }
      } catch (InterruptedException e) {
         System.out.println("Thread " +  threadName + " interrupted.");
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }
   
   public void start () {
      System.out.println("Starting " +  threadName );
      
      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
}

public class TestThread {

   public static void main(String args[]) {
      RunnableDemo R1 = new RunnableDemo("Thread-1");
      R1.start();
      
      RunnableDemo R2 = new RunnableDemo("Thread-2");
      R2.start();
   }   
}

Это даст следующий результат —

Выход

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.

Создать поток, расширяя класс потока

Второй способ создания потока — это создание нового класса, расширяющего класс Thread, с помощью следующих двух простых шагов. Этот подход обеспечивает большую гибкость в обработке нескольких потоков, созданных с использованием доступных методов в классе Thread.

Шаг 1

Вам нужно будет переопределить метод run (), доступный в классе Thread. Этот метод обеспечивает точку входа для потока, и вы поместите всю свою бизнес-логику в этот метод. Ниже приведен простой синтаксис метода run ():

public void run( )

Шаг 2

После создания объекта Thread его можно запустить, вызвав метод start () , который выполняет вызов метода run (). Ниже приведен простой синтаксис метода start ():

void start( );

пример

Вот предыдущая программа, переписанная для расширения темы —

Live Demo

class ThreadDemo extends Thread {
   private Thread t;
   private String threadName;
   
   ThreadDemo(String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }
   
   public void run() {
      System.out.println("Running " +  threadName );
      
      try {

         for(int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);
            
            // Let the thread sleep for a while.
            Thread.sleep(50);
         }
      } catch (InterruptedException e) {
         System.out.println("Thread " +  threadName + " interrupted.");
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }
   
   public void start () {
      System.out.println("Starting " +  threadName );
      
      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
}

public class TestThread {

   public static void main(String args[]) {
      ThreadDemo T1 = new ThreadDemo("Thread-1");
      T1.start();
      
      ThreadDemo T2 = new ThreadDemo("Thread-2");
      T2.start();
   }   
}

Это даст следующий результат —

Выход