Java中的线程状态分析
1. 线程有哪些状态
- 从操作系统视角
Linux系统中用top命令查看进程,pstree -p $pid查看线程树,top -Hp $pid查看进程内的线程。
top看到的是进程ID,不是main线程ID,而且状态是S。
- 可运行,1核虚拟机上有2个R线程,真正的running状态时 间很短,在linux上大约为5~20ms。
- 休眠,包括IO阻塞。
其它-I,Z,D与JVM关系不大,一般不用关注。
- 从JVM视角
用jstack命令可以查看。windows系统可以用jvisualvm.exe查看。
就绪-没有调用start()方法,jstack/top/jvisualvm.exe均不可见。
可运行-包括running,runnable,IO阻塞(系统中top命令可以查看), 因为在3种状态间的变换是由操作系统决定,而不是由JVM 决定。
休眠-sleep,不需要持有锁,如果持有锁也不释放。
等待-wait,需要持有锁,否则抛异常,调用后释放锁。与 notify/notifyall配合使用时,需要先wait,后notify/notifyall。 唤醒或等待超时后进入监视状态。
驻留-park,interrupt和unpark都能唤醒park线程,但是interrupt 的线程醒来不抛异常,也不清除中断标志。而且不要求 park/unpark调用先后顺序,可直接针对具体某一个线程。
监视-等待锁释放,不可中断。
2. 定位JVM中的线程问题
步骤如下:
(1)top命令找到占用CPU最多的进程
(2)Top -Hp $pid定位占用CPU最多的线程,线程ID是10进制
(3)jstack -l $pid > $file,输出结果中nid是系统线程ID,16进制, printf “%x\n” 10进制转16进制,printf “%d\n” 16进制转10进制