在 java 自带的工具 JVirtualVM 中线程有以下几种状态:
image先说结论,各状态含义如下,后面有详细的 demo 测试验证:
- 运行(runnable):正在运行中的线程。
- 休眠(timed_waiting):休眠线程,例如调用 Thread.sleep 方法。
- 等待(waiting):等待唤醒的线程,可通过调用 Object.wait 方法获得这种状态,底层实现是基于对象头中的 monitor 对象。
- 驻留(waiting):等待唤醒的线程,和等待状态类似,只不过底层的实现方式不同,处于这种状态的例子有线程池中的空闲线程,等待获取 reentrantLock 锁的线程,调用了 reentrantLock 的 condition 的 await 方法的线程等等,底层实现是基于 Unsafe 类的 park 方法,在 AQS 中有大量的应用。
- 监视(blocked):等待获取 monitor 锁的线程,例如等待进入 synchronize 代码块的线程。
代码测试
private static final ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
private static final ReentrantLock reentrantLockTest = new ReentrantLock();
public static void main(String[] args) {
//基于println方法中的synchronize代码块测试运行或者监视线程
Thread thread1 = new Thread(() -> {
while (true) {
System.out.println("运行或者监视线程1");
}
}, "运行或者监视线程1");
thread1.start();
//基于println方法中的synchronize代码块测试运行或者监视线程
Thread thread2 = new Thread(() -> {
while (true) {
System.out.println("运行或者监视线程2");
}
}, "运行或者监视线程2");
thread2.start();
//monitor对象等待线程
Object lock = new Object();
Thread thread3 = new Thread(() -> {
synchronized (lock) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "等待线程synchronized");
thread3.start();
//reentrantLock中的条件对象调用await方法线程为驻留线程
ReentrantLock reentrantLock = new ReentrantLock();
Condition condition = reentrantLock.newCondition();
Thread thread4 = new Thread(() -> {
reentrantLock.lock();
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
reentrantLock.unlock();
}
}, "等待线程reentrantLock");
thread4.start();
//休眠线程
Thread thread5 = new Thread(() -> {
try {
Thread.sleep(1000000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "休眠线程");
thread5.start();
Thread thread6 = new Thread(ThreadTest::lockMethod, "reentrantLock运行线程");
thread6.start();
//等待获取reentrantLock的线程为驻留线程
Thread thread7 = new Thread(() -> {
try {
TimeUnit.MICROSECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
lockMethod();
}, "reentrantLock监视线程");
thread7.start();
//线程池中的空闲线程为驻留线程
singleThreadExecutor.execute(() -> {
//线程池中的线程是懒加载,需要运行任务之后才会产生线程
System.out.println("驻留线程运行");
});
}
private static void lockMethod() {
reentrantLockTest.lock();
try {
while (true) {
}
} finally {
reentrantLockTest.unlock();
}
}
//println源码也简单贴一下
//java.io.PrintStream#println(java.lang.String)
public void println(String x) {
//this表示System.out这个PrintStream对象
synchronized (this) {
print(x);
newLine();
}
}
以上代码运行之后,打开 JVirtualVM 查看线程如下:
image根据代码的顺序从上至下讲:
-
两个运行或者监视线程的 System.out.println() 语句因为抢同一个 synchronize 锁,可以很明显的看出是在交替运行,状态分别处于运行和监视状态。
-
等待线程 synchronize 因为调用了 Object 的 wait 方法,一直处于等待状态。
-
休眠线程省略。
-
重点是和 reentrantLock 锁相关的三个线程,注意下上图中有一个地方写错了,等待线程 reentrantLock,实际应该是驻留线程 reentrantLock,可以看到无论是通过 condition 的 await 方法,还是在阻塞等待锁的过程中,都是处于驻留状态,而不是我一开始预想的等待状态,通过查看源码后发现它们最终都调用了 Unsafe 的 park 方法,后续的线程 dump 也能验证这一点。
-
pool- 1-threadpool-1 就是那个线程池,因为里面的线程处于空闲状态,也属于驻留。
网友评论