监控 Java 线程时,首先要关注的就是线程的运行状态。
一般来说,Java 线程有 6 种状态:
- NEW
- RUNNABLE
- WAITING & TIMED_WAITING
- SLEEP
- TERMINATED
- BLOCK
下面,用代码示例一下各个状态
1. NEW & TERMINATED
这两个状态比较特殊,分别出现在线程运行之前和线程运行之后。
这里所说的运行指调用线程的start()
方法。
代码:
虽然没有重写run
方法,线程会很快结束。但如果在start()
后直接调用getState()
的话,仍然会返回RUNNABLE,所以耐心的等上一秒吧。
2. RUNNABLE
我们开线程的目的就是要让它跑起来,所以这个状态可以说是线程的主要状态。
它表示线程正如我们预期的一样正在运行。
代码:
运行时,程序会在标准输出里不断输出 running。
下面是用 jvisualvm 监控到的情况:
图中的 runnable 线程就是我们在代码中启动的线程。
3. SLEEP
休眠状态下,线程不能被唤醒;必须等到休眠时间结束线程才能回到可执行状态。
让线程进入状态需要调用Thread
类的sleep
方法。调用时指定好需要休眠的时间,线程就可以美美的睡上一觉了。
代码:
jvisualvm 中的情况:
注:如果用线程 dump 查看,会发现 sleep 线程标示的是 TIMED_WATING
—更新—
但在 TIMED_WATING 后会显示 (sleeping) 作为与 wait 调用的区分
4.WAITING & TIMED_WAITING
和休眠类似,等待状态下的线程也没有在运行。但是等待下的线程可以随时被唤醒。
WAITING 和 TIMED_WAITING 都是调用wait
方法后的状态。区别在于 WATING 没有指定时间,除非被唤醒,否则会一直等下去。而 TIMED_WAITING 因为指定了时间,即使不被唤醒,也会在指定时间到达之后回到可执行状态。
代码:
jvisualvm 中的情况:
线程 dump 中的情况:
–更新–
可以看到在 TIMED_WATING 后有显示 (on object monitor)
表示调用的是 wait, 而不是 sleep
5.BLOCK
在线程中,可以使用 sychronized
关键字锁住某些资源,以保证其它线程不能同时访问。如果这时其它线程需要这个资源,就会进入阻塞状态。
如果,两个线程同时需要对方锁住的资源,而这些资源又不能被释放,那就会形成死锁。
这里就用死锁来示例阻塞状态
代码:
jvisualvm 中的情况: