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();
пример
Вот пример, который создает новый поток и запускает его:
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( );
пример
Вот предыдущая программа, переписанная для расширения темы —
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(); } }
Это даст следующий результат —
Выход