(удобнее просматривать исходный код на горизонтальном экране мобильного телефона)
Примечание. Часть анализа исходного кода Java основана на версии java8, если не указано иное.
Введение
Всем известно, что у потоков есть жизненный цикл, но брат Тонг может сказать вам, что почти ни одна статья в Интернете не является полностью правильной.
распространенные ошибкиБывают: состояние готовности, состояние выполнения (RUNNING), состояние неработоспособности, состояние прервано, только блокировка без состояния ожидания, каракули блок-схемы и т. д. Самая распространенная ошибка заключается в том, что для потоков существует всего 5 состояний.
В сегодняшней статье будет подробно объяснен жизненный цикл потоков и проанализирована логика изменения состояния потоков в синхронизированных блокировках и блокировках на основе AQS.
Поэтому, студенты, которые не знают о синхронизированных блокировках и принципах AQS (исходный код), пожалуйста, прочитайте предыдущие статьи Tong Ge, чтобы ознакомиться с содержанием этих двух частей, иначе вы точно не вспомните упомянутый здесь жизненный цикл потока.
вопрос
(1) Каковы состояния потока?
(2) В каком состоянии находится поток на каждом этапе синхронизированной блокировки?
(3) Каково состояние потока на каждом этапе повторной блокировки и условной блокировки?
Сначала перейдите к исходному коду
Что касается жизненного цикла потоков, мы можем посмотреть наjava.lang.Thread.State
Этот класс, который является классом внутреннего перечисления потока, определяет различные состояния потока и имеет четкие аннотации.
public enum State {
/**
* 新建状态,线程还未开始
*/
NEW,
/**
* 可运行状态,正在运行或者在等待系统资源,比如CPU
*/
RUNNABLE,
/**
* 阻塞状态,在等待一个监视器锁(也就是我们常说的synchronized)
* 或者在调用了Object.wait()方法且被notify()之后也会进入BLOCKED状态
*/
BLOCKED,
/**
* 等待状态,在调用了以下方法后进入此状态
* 1. Object.wait()无超时的方法后且未被notify()前,如果被notify()了会进入BLOCKED状态
* 2. Thread.join()无超时的方法后
* 3. LockSupport.park()无超时的方法后
*/
WAITING,
/**
* 超时等待状态,在调用了以下方法后会进入超时等待状态
* 1. Thread.sleep()方法后【本文由公从号“彤哥读源码”原创】
* 2. Object.wait(timeout)方法后且未到超时时间前,如果达到超时了或被notify()了会进入BLOCKED状态
* 3. Thread.join(timeout)方法后
* 4. LockSupport.parkNanos(nanos)方法后
* 5. LockSupport.parkUntil(deadline)方法后
*/
TIMED_WAITING,
/**
* 终止状态,线程已经执行完毕
*/
TERMINATED;
}
блок-схема
Аннотация каждого состояния в жизненном цикле потока завершена, давайте посмотрим на поток между состояниями:
как насчет этого? Это сложно? Брат Тонг проверил почти всю информацию в Интернете, и нет статьи, полностью рисующей эту блок-схему.Вот брат Тонг, чтобы объяснить их одну за другой:
(1) Для удобства пояснения разделим блокировки на две категории, одна — синхронизированные блокировки, другая — блокировки на основе AQS (в качестве примера возьмем реентерабельные блокировки), то есть LockSupport.park()/parkNanos(). /parkUntil() блокирует несколько методов;
(2) Будь то синхронизированная блокировка или блокировка на основе AQS, внутренняя часть разделена на две очереди, одна из которых представляет собой очередь синхронизации (очередь AQS), а другая — очередь ожидания (очередь условий);
(3) Для внутреннего вызова метода object.wait()/wait(timeout) или condition.await()/await(timeout) поток сначала входит в очередь ожидания, а после notify()/signal() или timeout , войдет в очередь на синхронизацию;
(4) Четко указано, что состояние BLOCKED будет иметь это состояние только тогда, когда поток находится в очереди синхронизированной синхронизации, и любая другая ситуация не имеет ничего общего с этим состоянием;
(5) Для синхронизированного, когда поток выполняется синхронно, если блокировка получена немедленно (без входа в очередь синхронизации), поток находится в состоянии RUNNABLE;
(6) Для синхронизированного, когда поток выполняется синхронно, если блокировка не может быть получена (непосредственно входит в очередь синхронизации), поток находится в состоянии БЛОКИРОВКИ;
(5) Для синхронизированной внутренней части после вызова object.wait() поток находится в состоянии WAITING (входя в очередь ожидания);
(6) Для синхронизированной внутренней части поток находится в состоянии TIMED_WAITING (входит в очередь ожидания) после вызова object.wait(timeout);
(7) Для синхронизированной внутренней части после вызова object.wait() и получения уведомления(), если поток немедленно получает блокировку (то есть не входит в очередь синхронизации), поток находится в состоянии RUNNABLE;
(8) Для синхронизированной внутренней части после вызова object.wait(timeout) и получения уведомления(), если поток немедленно получает блокировку (то есть не входит в очередь синхронизации), поток находится в состоянии RUNNABLE;
(9) Для синхронизированной внутренней части после вызова object.wait(timeout) и истечения времени ожидания, если поток немедленно получает блокировку (то есть не входит в очередь синхронизации), поток находится в состоянии RUNNABLE;
(10) Для синхронизированной внутренней части после вызова object.wait() и получения уведомления(), если поток не может получить блокировку (то есть входит в очередь синхронизации), поток находится в состоянии BLOCKED;
(11) Для синхронизированной внутренней части после вызова object.wait(timeout) и уведомления() или тайм-аута, если поток не может получить блокировку (то есть входит в очередь синхронизации), поток находится в состоянии BLOCKED. ;
(12) Для повторных блокировок, когда поток выполняет lock.lock(), если блокировка получена немедленно (без входа в очередь синхронизации), поток находится в состоянии RUNNABLE;
(13) Для повторных блокировок, когда поток выполняет lock.lock(), если блокировка не может быть получена (непосредственно входит в очередь синхронизации), поток находится в состоянии WAITING;
(14) Внутри реентерабельной блокировки после вызова condition.await() поток находится в состоянии WAITING (вход в очередь ожидания);
(15) Внутри реентерабельной блокировки после вызова condition.await(timeout) поток находится в состоянии TIMED_WAITING (вход в очередь ожидания);
(16) Внутри реентерабельной блокировки после вызова условия. ;
(17) Внутри реентерабельной блокировки после вызова condition.await(timeout) и обработки signal(), если поток получает блокировку немедленно (то есть не входит в очередь синхронизации), поток находится в состоянии RUNNABLE. состояние;
(18) Внутри повторно входимой блокировки после вызова условия. ;
(19) Внутри повторно входимой блокировки после вызова condition.await() и функции signal(), если поток не может получить блокировку (то есть входит в очередь синхронизации), поток находится в состоянии WAITING;
(20) Внутри повторной блокировки после вызова условия. состояние ОЖИДАНИЯ;
(21) Для реентерабельных блокировок, если блокировка по-прежнему не может быть получена после внутреннего вызова condition.await() и после вызова signal(), фактически она испытала два переключения состояния WAITING, одно из которых ожидает очередь. , один синхронизирует очередь;
(22) Для реентерабельных блокировок, если внутренне вызывается условие.
Чтобы облегчить понимание, брат Тонг подробно разделен на каждую статью, пожалуйста, внимательно прочитайте ее.
прецедент
Прочитав предыдущую часть, вы должны захотеть узнать, как проверить.Далее брат Тонг расскажет о методе проверки и сначала даст тестовые примеры.
public class ThreadLifeTest {
public static void main(String[] args) throws IOException {
Object object = new Object();
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
new Thread(()->{
synchronized (object) {
try {
System.out.println("thread1 waiting");
object.wait();
// object.wait(5000);
System.out.println("thread1 after waiting");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "Thread1").start();
new Thread(()->{
synchronized (object) {
try {
System.out.println("thread2 notify");
// 打开或关闭这段注释,观察Thread1的状态
// object.notify();【本文由公从号“彤哥读源码”原创】
// notify之后当前线程并不会释放锁,只是被notify的线程从等待队列进入同步队列
// sleep也不会释放锁
Thread.sleep(10000000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "Thread2").start();
new Thread(()->{
lock.lock();
System.out.println("thread3 waiting");
try {
condition.await();
// condition.await(200, (TimeUnit).SECONDS);
System.out.println("thread3 after waiting");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}, "Thread3").start();
new Thread(()->{
lock.lock();
System.out.println("thread4");
// 打开或关闭这段注释,观察Thread3的状态
// condition.signal();【本文由公从号“彤哥读源码”原创】
// signal之后当前线程并不会释放锁,只是被signal的线程从等待队列进入同步队列
// sleep也不会释放锁
try {
Thread.sleep(1000000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}, "Thread4").start();
}
}
Откройте или закройте код в разделе комментариев выше, используйте режим RUN IDEA для запуска кода, а затем нажмите кнопку камеры (jstack) слева, чтобы просмотреть статус каждого потока.
Примечание. Не используйте режим DEBUG, режим DEBUG переходит в состояние WAITING, это потрясающе.
пасхальные яйца
На самом деле, эта статья изначально предназначалась для написания жизненного цикла пула потоков, но я слишком много написал о жизненном цикле потока, давайте вместе узнаем о жизненном цикле пула потоков в следующей статье.
Добро пожаловать, чтобы обратить внимание на мою общедоступную учетную запись «Брат Тонг читает исходный код», проверить больше статей из серии исходного кода и поплавать в океане исходного кода с братом Тонгом.