Thread(Поток)
Что это
Thread - создание потоков вручную с использованием конструктора Thread позволяет получить максимальный
контроль, но снижает гибкость. Рекомендуется использовать ExecutorService для более управляемого подхода.
Thread static методы:
- currentThread() - возвращает текущий поток. Можно получить id/имя потока, сделать join() и тд.
- sleep() - останавливает поток на количество переданных миллисекунд. Поток переходит в состояние
TIMED_WAITING. Не стоит использовать ее для ожидания условий, используйте wait() и notify() для работы
с мониторами.
- interrupted() - прервать поток. Если он вызван во время сна, бросится исключение.
Thread методы(после получения через currentThread()):
- void run() - описывает реализацию работы потока. При запуске - выполнит в том же потоке.
- start() - запускает выполнение метода run, в отдельном потоке.
- long getId()
- String getName()
- join() - блокирует вызывающий поток до завершения другого(переданного) потока.
- join(final long millis) - join() с указание времени, по завершению которого проток продолжиться без ожидания.
- void setPriority(int priority) - задать приоритет потока от 1 до 10.
- int getPriority() - получить приоритет потока.
- isAlive() - true, если поток "жив", то есть после старта и до завершения.
Exception который появился в отдельном потоке не вернется в main поток. По этому должен быть обработан
в своём потоке.
Планировщик потоков
Планировщик потоков - часть JVM, решает какой поток должен выполнится в каждый конкретный момент времени
и какой поток нужно приостановить. И меняет им состояния.
Гарантии:
- Java НЕ гарантирует, что потоки будут выполнены в том порядке в котором они были запущены.
- Нет гарантии, что если поток начал свое выполнение, то он выполнит свою работу не прерываясь.
- При каждом новом запуске программы, результат может быть разным.
- Гарантируется, что каждый поток начнет свою работу и будет выполнять пока не закончит.
- Внутри одного потока действия выполняются в предсказуемом порядке.
Методы позволяющие влиять на планировщика потоков
java.lang.Thread
- public static void sleep(long millis) throws InterruptedException
- public static void yield()
- public final void join() throws InterruptedException
- public final void setPriority(int newPriority)
java.lang.Object
- public final void wait() throws InterruptedException - выйди из синхронного блока, освободить монитор,
остановиться перед ним, получить статус waiting, вызвать метод notify().
- public final void notify() - разбудит первого в очереди(массив) монитора.
- public final void notifyAll()
Thread.priority
Priority - приоритет используется для очередности переданных задач. Но это не заблокирует задачи с малым
приоритетом, они просто будут выполняться реже.
Каждому потоку исполнения в Java присваивается свой приоритет от 1 до 10(5 по умолчанию), который определяет
поведение данного потока по отношению к другим потокам в планировщике потоков.
Стадии жизненного цикла потока(Состояние потока)
- new - поток создан, но не запущен. new Thread().
- runnable - поток выполняется JVM. start().
- blocked - потом заблокирован, и ждет освобождения монитора.
- waiting - в этом состоянии находится поток, который бесконечно ожидает выполнения другим потоком
определенного действия.
- timed_waiting - в этом состоянии находится поток, ожидающий выполнения действия другим потоком в течение
указанного времени ожидания.
- terminated - поток завершен. Также потоки не могут быть запущены повторно.
Daemon
Daemon - поток-демон. Поток, который работает в фоновом режиме и не блокирует завершение программы.
Создаётся путем переключение переменой boolean методом setDaemon(), перед запуском потока(start()).
isDaemon() - метод для проверки потока, демон или нет.
Может создавать только потоки-демоны. Даже если явно не указывать setDaemon().
Завершают run() без выполнение finally{}.
Завершаются немедленно(не ждет конца выполнения) - при завершении всех потоков не демонов.
- MIN_PRIORITY(константа 1)
- NORM_PRIORITY(константа 5) (приоритет по умолчанию)
- MAX_PRIORITY(константа 10)
ThreadLocal
ThreadLocal - специальный механизм, позволяющий каждому потоку иметь свою собственную копию переменной,
изолированную от других потоков.
ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
threadLocal.set(100); // Устанавливается только для текущего потока
Integer value = threadLocal.get(); // Получает значение текущего потока
Когда использовать
- Нужна потоковая изоляция без синхронизации. Когда данные должны быть уникальны для каждого потока,
но не хочется использовать synchronized.
- Переменные на время жизни потока. Например, хранение ID запроса, транзакции, даты, пользователя и т. д.,
которые нужны во многих местах, но только для текущего потока.
- В Web-приложениях. Хранение текущего пользователя или сессии без передачи параметров по цепочке методов.
- При работе с небезопасными объектами. Например, SimpleDateFormat не является потокобезопасным, но с
ThreadLocal его можно безопасно использовать.
Важно: подводные камни
- Утечки памяти: особенно в сервлет-контейнерах (Tomcat), если ThreadLocal не очищать после использования
(remove()).
- Не подходит для передачи между потоками: каждый поток видит только свою копию.