JVisualVM 是 JDK 自带的性能检测工具,路径在 %JAVA_HOME%/bin 下面。双击 jvisualvm.exe 可以打开程序,程序界面如下:
上图中,左边的应用程序“本地”下面有三个 java 进程,分别是 IntelliJ Platform、VisualVM 和 org.jetbrains.jps.cmdline.Launcher。双击 org.jetbrains.jps.cmdline.Launcher java 进程,分析该进程的详细信息,如下图:
上图中,展示了该 java 进程的线程信息。在图片的右下角有五个图例,用来表示线程的状态,本文将逐一介绍这些线程状态。
处于这种状态的线程对于操作系统而言,要么是正在占用CPU时间片运行的线程,要么是已经就绪的线程,只要有CPU时间片分配到,就可以直接运行,对应 Java 中 Runnable 状态。实例:
public class RunningThreadState { public static void main(String[] args) { Thread t = new Thread(new Runnable() { public void run() { while(true) {} } }, "thread-running"); t.start(); } }
运行效果如下图:
处于睡眠状态的线程,通过调用Thread.sleep()方法让线程进行这种状态,此种状态的线程不占用CPU,但是不释放锁资源。实例:
public class SleepingThreadState { public static void main(String[] args) { Thread t = new Thread(new Runnable() { public void run() { while (true) { try { Thread.sleep(1000); }catch (InterruptedException e) {} } } }, "thread-sleeping"); t.start(); } }
运行效果如下图:
通过调用 Object.wait()、Thread.join() 等方法让线程进入这种状态,这种状态的线程不仅会让出 CPU 资源,也会让出所占用的锁资源。实例:
public class WaitThreadState { public static void main(String[] args) { final Thread t = new Thread(new Runnable() { public void run() { while (true){} } }); t.start(); Thread t1 = new Thread(new Runnable() { public void run() { try { // 等待线程 t 终止 t.join(); } catch (InterruptedException e) {} } }, "thread-waiting"); t1.start(); } }
运行效果如下图:
通过调用 LockSupport 类中的一些列 park 方法进行此种状态。这种状态是线程没有占用锁,但是可以直接让线程让出 CPU,其他的方法都提到了锁的概念。实例:
public class ParkThreadState { public static void main(String[] args) { // LockSupport.park 会让线程进入 park 状态, // 其实就是不涉及锁的情况下,直接让线程让出 CPU 资源 Thread t = new Thread(new Runnable() { public void run() { LockSupport.park(); } }, "thread-park"); t.start(); } }
运行效果如下图:
通过抢占 synchronized 中的锁而进入的状态。实例:
public class MonitorThreadState { public static void main(String[] args) { Thread t1 = new Thread(new Runnable() { public void run() { say(); } }, "thread-monitor1"); t1.start(); Thread t2 = new Thread(new Runnable() { public void run() { say(); } }, "thread-monitor2"); t2.start(); } // 某个线程获得锁后就死循环不释放锁,另一个线程一直等待该锁 private synchronized static void say() { while(true) { try { // 下面两个操作都会让出 CPU,但是不释放锁资源 // 这就导致另一个线程永远也不能获得 say() 方法的锁 System.out.println("synchronized:" + Thread.currentThread()); LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(500)); Thread.sleep(500); }catch (Exception e) {} } } }
运行效果如下图: