目录
Java的主要并发手段就是多线程,并且Java线程Thread直接使用了操作系统内存的线程(一对一关系),那么Thread的状态和生命周期(状态的转换)就显得尤为重要。必要时查看线上项目的线程dump也是必要的技能。
Thread的状态就是其内部类State,如下:
public static enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
private State() {}
}
1、线程状态
NEW
创建完成(new Thread 或者Runnable、Callable)就绪状态,只是在Java中创建好,操作系统内核还没有创建该线程
RUNNABLE
调用完线程的start方法(会调用native的start0方法)后,切换为运行或可运行状态,可以被CPU的时间切片切中 执行任务
BLOCKED
阻塞状态
WAITING
等待状态
TIMED_WAITING
限时等待状态
TERMINATED
终止状态,生命周期结束
2、线程状态的转换
由上面的状态可以看出,只有RUNNABLE状态可以到TERMINATED状态,结合之前分析的 两阶段终止(Two-Phase Termination)模式,如下图:
NEW -> RUNNABLE
当先被创建后,可以调用线程的start方法,才会真正在操作系统层面创建线程,转换为可以被CPU执行状态
RUNNABLE -> BLOCKED
使用synchronized只允许一个线程进入临界区执行,则其他线程进入Blocked状态
BLOCKED -> RUNNABLE
上面的情况,当线程出临界区后,则会将刚才的线程切换为Runnable状态
RUNNABLE -> WAITING
1、在synchronized内部调用了Thread的waiting方法时,线程转换为waiting状态。其实就是管程里面,进入了条件等待队列中
2、在主线程调用子线程的join方法,等待子线程执行完任务,这是主线转换为waiting状态
3、LockSupport.park方法【juc包下全是使用该方式】
WAITING -> RUNNABLE
1、上面join等待子线程执行完任务后,主线程会转换为Runnable状态
2、LockSupport.unpark(Thread)方法
RUNNABLE -> TIMED_WAITING
Thread.sleep(long millis)
Object.wait(long timeout)
Thread.join(long millis)
LockSupport.parkNanos(Object blocker, long deadline)
LockSupport.parkUntil(long deadline)
RUNNABLE -> TERMINATED
1、线程的run方法执行完成,自动切换到该状态
2、没有执行完,异常终止
1)、调用线程的stop方法【已废弃】,会真的杀死线程,如果线程持有ReenTrantLock则永远不会执行unpark方法,非常危险
2)、suspend【不建议】
3)、resume【不建议】
4)、调用线程的interrupted方法。比如:wait、sleep、join都会抛出检查异常InterruptedException,比如正在执行一个和耗时的任务,当前线程处于Waiting或者Timed_waiting状态,就可以调用该方法。主动检查:调用线程的isInterrupted方法自行判断。
整体大致如下图: