Java является многопоточным языком программирования, а это значит, что с помощью него мы можем разрабатывать многопоточные программы. Многопоточная программа состоит из двух или более частей, которые могут выполняться одновременно, и каждая часть может одновременно обрабатывать разные задачи, оптимально используя доступные ресурсы, особенно если компьютер имеет несколько ЦП.
По определению, многозадачность – это совместное использование несколькими процессами общих ресурсов обработки, таких как ЦП. Многопоточность расширяет идею многозадачности на приложения, в которых вы можете разделить определенные операции в рамках одного приложения на отдельные потоки. Каждый из потоков может работать параллельно. ОС распределяет время обработки не только между различными приложениями, но и между каждым потоком в приложении.
Многопоточность позволяет создавать код таким образом, чтобы несколько действий могли выполняться одновременно в одной программе.
Жизненный цикл потока
В своем жизненном цикле поток проходит различные стадии. Например, поток создается, запускается, выполняется и затем останавливается. На следующей схеме показан полный жизненный цикл потока.
Ниже приведены этапы жизненного цикла:
- Новый− Новый поток начинает свой жизненный цикл в состоянии нового. Он сохраняет это состояние до тех пор, пока программа не запустит поток. Его также называют созданным потоком.
- Запущенный − После запуска нового потока он становится запущенным. Считается, что поток в этом состоянии выполняет свою задачу.
- Ожидающий − Иногда поток переходит в состояние ожидания, т.е. поток ожидает, пока другой поток выполнит задачу. Поток переходит обратно в запущенное состояние только после того, когда другой поток сигнализирует ожидающему потоку продолжить выполнение.
- Ожидающий с ограничением по времени − Запущенный поток может войти в состояние ожидания с ограничением по времени в течение определенного интервала времени. Поток в этом состоянии переходит обратно в запущенное состояние, когда истекает этот временной интервал или когда происходит событие, которого он ожидает.
- Остановленный− Запущенный поток переходит в остановленное состояние, когда он завершает свою задачу или иным образом завершается.
Приоритеты потоков
Каждый поток Java имеет приоритет, который помогает операционной системе определять порядок, в котором планируются потоки.
Приоритеты потоков Java находятся в диапазоне от MIN_PRIORITY (константа 1) до MAX_PRIORITY (константа 10). По умолчанию каждому потоку устанавливается приоритет NORM_PRIORITY (константа 5).
Потоки с более высоким приоритетом более важны для программы, и в первую очередь им должно выделяться процессорное время. Однако приоритеты потоков не могут гарантировать порядок, в котором выполняются потоки, и очень сильно зависят от платформы.
Создание потока путем реализации интерфейса Runnable
Если ваш класс предназначен для выполнения как поток, вы можете добиться этого, реализовав интерфейс 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("Создание " + threadName );
}
public void run() {
System.out.println("Выполнение " + threadName );
try {
for(int i = 4; i > 0; i--) {
System.out.println("Поток: " + threadName + ", " + i);
// Пусть поток немного подождет.
Thread.sleep(50);
}
} catch (InterruptedException e) {
System.out.println("Поток " + threadName + " прерван.");
}
System.out.println("Поток " + threadName + " завершается.");
}
public void start () {
System.out.println("Запуск " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
}
public class TestThread {
public static void main(String args[]) {
RunnableDemo R1 = new RunnableDemo( "Поток-1");
R1.start();
RunnableDemo R2 = new RunnableDemo( " Поток-2");
R2.start();
}
}
Это даст следующий результат:
Создание Поток-1
Запуск Поток-1
Создание Поток-2
Запуск Поток-2
Выполнение Поток-1
Поток: Поток-1, 4
Выполнение Поток-2
Поток: Поток-2, 4
Поток: Поток-1, 3
Поток: Поток-2, 3
Поток: Поток-1, 2
Поток: Поток-2, 2
Поток: Поток-1, 1
Поток: Поток-2, 1
Поток Поток-1 завершается.
Поток Поток-2 завершается.
Создание потока путем расширения класса Thread
Второй способ создания потока в Java заключается в создании нового класса, расширяющего класс 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("Создание " + threadName );
}
public void run() {
System.out.println("Выполнение " + threadName );
try {
for(int i = 4; i > 0; i--) {
System.out.println("Поток: " + threadName + ", " + i);
// Пусть поток немного подождет.
Thread.sleep(50);
}
} catch (InterruptedException e) {
System.out.println("Поток " + threadName + " прерывается.");
}
System.out.println("Поток " + threadName + " завершается.");
}
public void start () {
System.out.println("Запуск " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
}
public class TestThread {
public static void main(String args[]) {
ThreadDemo T1 = new ThreadDemo( "Поток-1");
T1.start();
ThreadDemo T2 = new ThreadDemo( "Поток-2");
T2.start();
}
}
Это даст следующий результат:
Создание Поток-1
Запуск Поток-1
Создание Поток-2
Запуск Поток-2
Выполнение Поток-1
Поток: Поток-1, 4
Выполнение Поток-2
Поток: Поток-2, 4
Поток: Поток-1, 3
Поток: Поток-2, 3
Поток: Поток-1, 2
Поток: Поток-2, 2
Поток: Поток-1, 1
Поток: Поток-2, 1
Поток Поток-1 завершается.
Поток Поток-2 завершается.
Методы потока
Ниже приводится список важных методов, доступных в классе Thread в Java.
№ |
Метод и описание |
1 |
public void start() |
2 |
public void run() |
3 |
public final void setName(String name) |
4 |
public final void setPriority(int priority) |
5 |
public final void setDaemon(boolean on) |
6 |
public final void join(long millisec) |
7 |
public void interrupt() |
8 |
public final boolean isAlive() |
Предыдущие методы вызываются для конкретного объекта Thread. Следующие методы в классе Thread являются статическими. Вызов одного из статических методов выполняет операцию в текущем запущенном потоке.
№ |
Метод и описание |
1 |
public static void yield() |
2 |
public static void sleep(long millisec) |
3 |
public static boolean holdsLock(Object x) |
4 |
public static Thread currentThread() |
5 |
public static void dumpStack() |
Пример
Следующая программа ThreadClassDemo демонстрирует некоторые из этих методов класса Thread. Рассмотрим класс DisplayMessage, который реализует Runnable:
// Название файла: DisplayMessage.java
// Создаем поток для реализации Runnable
public class DisplayMessage implements Runnable {
private String message;
public DisplayMessage(String message) {
this.message = message;
}
public void run() {
while(true) {
System.out.println(message);
}
}
}
Ниже приведен еще один класс, который расширяет класс Thread.
// Название файла: GuessANumber.java
// Создаем поток для расширения Thread
public class GuessANumber extends Thread {
private int number;
public GuessANumber(int number) {
this.number = number;
}
public void run() {
int counter = 0;
int guess = 0;
do {
guess = (int) (Math.random() * 100 + 1);
System.out.println(this.getName() + " угадываний " + guess);
counter++;
} while(guess != number);
System.out.println("** Верно!" + this.getName() + "за" + counter + "угадываний.**");
}
}
Ниже приведена основная программа, в которой используются выше определенные классы.
// Название файла: ThreadClassDemo.java
public class ThreadClassDemo {
public static void main(String [] args) {
Runnable hello = new DisplayMessage("Привет");
Thread thread1 = new Thread(hello);
thread1.setDaemon(true);
thread1.setName("привет");
System.out.println("Запуск потока привет...");
thread1.start();
Runnable bye = new DisplayMessage("Пока");
Thread thread2 = new Thread(bye);
thread2.setPriority(Thread.MIN_PRIORITY);
thread2.setDaemon(true);
System.out.println("Запуск потока пока...");
thread2.start();
System.out.println("Запуск потока3...");
Thread thread3 = new GuessANumber(27);
thread3.start();
try {
thread3.join();
} catch (InterruptedException e) {
System.out.println("Поток прерван.");
}
System.out.println("Запуск потока4...");
Thread thread4 = new GuessANumber(75);
thread4.start();
System.out.println("main() завершается...");
}
}
Это даст следующий результат. Вы можете пробовать этот пример снова и снова, и каждый раз вы будете получать разные результаты.
Вывод
Запуск потока привет...
Запуск потока пока...
Привет
Привет
Привет
Привет
Привет
Привет
Пока
Пока
Пока
Пока
Пока
.......
Основные концепции многопоточности Java
При выполнении многопоточного программирования на Java вы столкнетесь со следующими вопросами:
- Что такое синхронизация потоков?
- Обработка межпоточной связи
- Обработка взаимной блокировки потоков
- Основные операции с потоками
Оглавление
- 1. Java – Самоучитель для начинающих
- 2. Java – Обзор языка
- 3. Java – Установка и настройка
- 4. Java – Синтаксис
- 5. Java – Классы и объекты
- 6. Java – Конструкторы
- 7. Java – Типы данных и литералы
- 8. Java – Типы переменных
- 9. Java – Модификаторы
- 10. Java – Операторы
- 11. Java – Циклы и операторы цикла
- 11.1. Java – Цикл while
- 11.2. Java – Цикл for
- 11.3. Java – Улучшенный цикл for
- 11.4. Java – Цикл do..while
- 11.5. Java – Оператор break
- 11.6. Java – Оператор continue
- 12. Java – Операторы принятия решений
- 12.1. Java – Оператор if
- 12.2. Java – Оператор if..else
- 12.3. Java – Вложенный оператор if
- 12.4. Java – Оператор switch..case
- 12.5. Java – Условный оператор (? :)
- 13. Java – Числа
- 13.1. Java – Методы byteValue(), shortValue(), intValue(), longValue(), floatValue(), doubleValue()
- 13.2. Java – Метод compareTo()
- 13.3. Java – Метод equals()
- 13.4. Java – Метод valueOf()
- 13.5. Java – Метод toString()
- 13.6. Java – Метод parseInt()
- 13.7. Java – Метод Math.abs()
- 13.8. Java – Метод Math.ceil()
- 13.9. Java – Метод Math.floor()
- 13.10. Java – Метод Math.rint()
- 13.11. Java – Метод Math.round()
- 13.12. Java – Метод Math.min()
- 13.13. Java – Метод Math.max()
- 13.14. Java – Метод Math.exp()
- 13.15. Java – Метод Math.log()
- 13.16. Java – Метод Math.pow()
- 13.17. Java – Метод Math.sqrt()
- 13.18. Java – Метод Math.sin()
- 13.19. Java – Метод Math.cos()
- 13.20. Java – Метод Math.tan()
- 13.21. Java – Метод Math.asin()
- 13.22. Java – Метод Math.acos()
- 13.23. Java – Метод Math.atan()
- 13.24. Java – Метод Math.atan2()
- 13.25. Java – Метод Math.toDegrees()
- 13.26. Java – Метод Math.toRadians()
- 13.27. Java – Метод Math.random()
- 14. Java – Символы
- 14.1. Java – Метод Character.isLetter()
- 14.2. Java – Метод Character.isDigit()
- 14.3. Java – Метод Character.isWhitespace()
- 14.4. Java – Метод Character.isUpperCase()
- 14.5. Java – Метод Character.isLowerCase()
- 14.6. Java – Метод Character.toUpperCase()
- 14.7. Java – Метод Character.toLowerCase()
- 14.8. Java – Метод Character.toString()
- 15. Java – Строки
- 15.1. Java – Метод charAt()
- 15.2. Java – Метод compareTo()
- 15.3. Java – Метод compareToIgnoreCase()
- 15.4. Java – Метод concat()
- 15.5. Java – Метод contentEquals()
- 15.6. Java – Метод copyValueOf()
- 15.7. Java – Метод endsWith()
- 15.8. Java – Метод equals()
- 15.9. Java – Метод equalsIgnoreCase()
- 15.10. Java – Метод getBytes()
- 15.11. Java – Метод getChars()
- 15.12. Java – Метод hashCode()
- 15.13. Java – Метод indexOf()
- 15.14. Java – Метод intern()
- 15.15. Java – Метод lastIndexOf()
- 15.16. Java – Метод length()
- 15.17. Java – Метод matches()
- 15.18. Java – Метод regionMatches()
- 15.19. Java – Метод replace()
- 15.20. Java – Метод replaceAll()
- 15.21. Java – Метод replaceFirst()
- 15.22. Java – Метод split()
- 15.23. Java – Метод startsWith()
- 15.24. Java – Метод subSequence()
- 15.25. Java – Метод substring()
- 15.26. Java – Метод toCharArray()
- 15.27. Java – Метод toLowerCase()
- 15.28. Java – Метод toString()
- 15.29. Java – Метод toUpperCase()
- 15.30. Java – Метод trim()
- 15.31. Java – Метод valueOf()
- 15.32. Java – Классы StringBuilder и StringBuffer
- 15.32.1. Java – Метод append()
- 15.32.2. Java – Метод reverse()
- 15.32.3. Java – Метод delete()
- 15.32.4. Java – Метод insert()
- 15.32.5. Java – Метод replace()
- 16. Java – Массивы
- 17. Java – Дата и время
- 18. Java – Регулярные выражения
- 19. Java – Методы
- 20. Java – Потоки ввода/вывода, файлы и каталоги
- 20.1. Java – Класс ByteArrayInputStream
- 20.2. Java – Класс DataInputStream
- 20.3. Java – Класс ByteArrayOutputStream
- 20.4. Java – Класс DataOutputStream
- 20.5. Java – Класс File
- 20.6. Java – Класс FileReader
- 20.7. Java – Класс FileWriter
- 21. Java – Исключения
- 21.1. Java – Встроенные исключения
- 22. Java – Вложенные и внутренние классы
- 23. Java – Наследование
- 24. Java – Переопределение
- 25. Java – Полиморфизм
- 26. Java – Абстракция
- 27. Java – Инкапсуляция
- 28. Java – Интерфейсы
- 29. Java – Пакеты
- 30. Java – Структуры данных
- 30.1. Java – Интерфейс Enumeration
- 30.2. Java – Класс BitSet
- 30.3. Java – Класс Vector
- 30.4. Java – Класс Stack
- 30.5. Java – Класс Dictionary
- 30.6. Java – Класс Hashtable
- 30.7. Java – Класс Properties
- 31. Java – Коллекции
- 31.1. Java – Интерфейс Collection
- 31.2. Java – Интерфейс List
- 31.3. Java – Интерфейс Set
- 31.4. Java – Интерфейс SortedSet
- 31.5. Java – Интерфейс Map
- 31.6. Java – Интерфейс Map.Entry
- 31.7. Java – Интерфейс SortedMap
- 31.8. Java – Класс LinkedList
- 31.9. Java – Класс ArrayList
- 31.10. Java – Класс HashSet
- 31.11. Java – Класс LinkedHashSet
- 31.12. Java – Класс TreeSet
- 31.13. Java – Класс HashMap
- 31.14. Java – Класс TreeMap
- 31.15. Java – Класс WeakHashMap
- 31.16. Java – Класс LinkedHashMap
- 31.17. Java – Класс IdentityHashMap
- 31.18. Java – Алгоритмы Collection
- 31.19. Java – Iterator и ListIterator
- 31.20. Java – Comparator
- 32. Java – Дженерики
- 33. Java – Сериализация
- 34. Java – Сеть
- 34.1. Java – Обработка URL
- 35. Java – Отправка Email
- 36. Java – Многопоточность
- 36.1. Java – Синхронизация потоков
- 36.2. Java – Межпоточная связь
- 36.3. Java – Взаимная блокировка потоков
- 36.4. Java – Управление потоками
- 37. Java – Основы работы с апплетами
- 38. Java – Javadoc