前言
经常在面试的时候问到Java的线程生命周期,虽然实际运用中不会关注这些。但了解Java线程的实现,调度和生命周期,对编程就会豁然开朗。
1. 线程的实现
线程是比进程更轻量级的调度执行单位,线程的引入,可以把一个进程的资源和执行调度分开,各个线程既可以共享进程资源(内存地址、文件IO等),又可以独立调度,线程是CPU调度的基本单位。
1.1 内核线程实现
直接由操作内核支持的线程,由内核完成线程的切换。
程序一般不会直接使用内核线程,而是使用内核线程的一种高级接口-轻量级进程。
局限性:需要系统调度,系统调度代价大,需要在用户态和内核态来回切换;内核进程数量有限。
1.2 用户线程实现
完全建立在用户空间的线程库上,系统内核无感知。JDK1.2之前使用这种模式。
优势:性能极强。用户线程的建立,同步,销毁和调度完全在用户态中完成,操作非常快,低消耗,无需切换内核态。
局限性:所有操作都需要自己实现,逻辑极其复杂。
1.3 用户线程和轻量级进程混合实现
用户线程负责创建,切换,析构等操作,而轻量级进程则负责用户线程和内核的交互,使用内核提供线程调度和处理器映射能力。JDK1.2开始支持。
2. Java线程的调度
就是对线程分配处理器的使用权。
2.1. 协同式
一个线程干完活通知系统让另一个线程干活,实现简单;执行时间不受控制,一个线程阻塞,会直接阻塞整个进程。
2.2. 抢占式
系统分配线程的执行时间,受系统控制。
3. 线程状态
定义在Thread的内部枚举,Java线程总共有6种状态。
/**
* A thread state. A thread can be in one of the following states:
* <ul>
* <li>{@link #NEW}<br>
* A thread that has not yet started is in this state.
* </li>
* <li>{@link #RUNNABLE}<br>
* A thread executing in the Java virtual machine is in this state.
* </li>
* <li>{@link #BLOCKED}<br>
* A thread that is blocked waiting for a monitor lock
* is in this state.
* </li>
* <li>{@link #WAITING}<br>
* A thread that is waiting indefinitely for another thread to
* perform a particular action is in this state.
* </li>
* <li>{@link #TIMED_WAITING}<br>
* A thread that is waiting for another thread to perform an action
* for up to a specified waiting time is in this state.
* </li>
* <li>{@link #TERMINATED}<br>
* A thread that has exited is in this state.
* </li>
* </ul>
*
* <p>
* A thread can be in only one state at a given point in time.
* These states are virtual machine states which do not reflect
* any operating system thread states.
*
* @since 1.5
* @see #getState
*/
public enum State {
/**
* Thread state for a thread which has not yet started.
*/
NEW,
/**
* Thread state for a runnable thread. A thread in the runnable
* state is executing in the Java virtual machine but it may
* be waiting for other resources from the operating system
* such as processor.
*/
RUNNABLE,
/**
* Thread state for a thread blocked waiting for a monitor lock.
* A thread in the blocked state is waiting for a monitor lock
* to enter a synchronized block/method or
* reenter a synchronized block/method after calling
* {@link Object#wait() Object.wait}.
*/
BLOCKED,
/**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the
* following methods:
* <ul>
* <li>{@link Object#wait() Object.wait} with no timeout</li>
* <li>{@link #join() Thread.join} with no timeout</li>
* <li>{@link LockSupport#park() LockSupport.park}</li>
* </ul>
*
* <p>A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called <tt>Object.wait()</tt>
* on an object is waiting for another thread to call
* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
* that object. A thread that has called <tt>Thread.join()</tt>
* is waiting for a specified thread to terminate.
*/
WAITING,
/**
* Thread state for a waiting thread with a specified waiting time.
* A thread is in the timed waiting state due to calling one of
* the following methods with a specified positive waiting time:
* <ul>
* <li>{@link #sleep Thread.sleep}</li>
* <li>{@link Object#wait(long) Object.wait} with timeout</li>
* <li>{@link #join(long) Thread.join} with timeout</li>
* <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
* <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
* </ul>
*/
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
*/
TERMINATED;
}
状态的转换如图所示
3.1 新建(NEW)
创建后尚未启动的线程处于这个状态
这个时候从本质上仅是一个Thread对象。
3.2 运行(RUNNABLE)
Runnable包括了操作系统线程状态中的Running和Ready,也就是处于此状态的线程可能正在运行,也有可能正在等待CPU为它分配执行时间。
3.3 无限期等待(Waiting)
处于这种状态的线程不会被分配CPU执行时间,它们要等待被其它线程显示地唤醒。以下方法会让线程陷入无限期等待状态:
1)没有设置timeout参数的Object.wait()方法。
2)没有设置timeout参数的Thread.join()方法。
3)LockSupport.park()方法。
3.4 限期等待(Timed Waiting)
处于这种状态的线程也不会被分配CPU执行时间,不过无需等待被其它线程显示地唤醒,在一定时间之后它们会由系统自动的唤醒。以下方法会让线程进入TIMED_WAITING限期等待状态:
1)Thread.sleep()方法
2)设置了timeout参数的Object.wait()方法
3)设置了timeout参数的Thread.join()方法
4)LockSupport.parkNanos()方法
5)LockSupport.parkUntil()方法
3.5 阻塞(Blocked)
线程被阻塞了,说明一下和等待状态的区别
阻塞状态:在等待着获取到一个排他锁,这个事件在另外一个线程放弃这个锁的时候发生
等待状态:在等待一段时间,或者唤醒动作的发生。在程序等待进入同步区域的时候,线程将进入这种状态。
3.6 结束(Terminated)
已终止线程
4. 线程状态的获取
Thread对象提供如下方法支持
/**
* Returns the state of this thread.
* This method is designed for use in monitoring of the system state,
* not for synchronization control.
*
* @return this thread's state.
* @since 1.5
*/
public State getState() {
// get current thread state
return sun.misc.VM.toThreadState(threadStatus);
}
5. jstack查看线程的状态
5.1 jps命令
jps
左边就是进程ID,俗称PID
5.2 查看进程下的线程
ps -mp pid -o THREAD, tid, time
虚拟机跑得,没部署应用,图中TID即是线程ID
5.3 16进制转换
printf "%x\n" 线程tid
5.4 生成Java栈日志
jstack 进程ID > 1.log
5.5 日志搜索
grep 16进制线程ID 1.log
"TestThread" prio=10 tid=0x0000xxxxxxxxx nid=0x8e6 in Object.wait()
java.lang.Thread.State : RUNNABLE
at xxx.xxx.xxx.class.xxxmethod(xx.java:xx行)
引用: JVM高级特性与最佳实践