本文将从源码角度分析Java线程的各种状态以及进入该状态所对应的操作。OpenJDK版本
代码语言:javascript复制➜ jdk hg id
76072a077ee1 jdk-11 28
首先用jstack命令看下Java线程的状态及堆栈信息(删减了无用内容)
代码语言:javascript复制"TEST_while(true)" #12 ... runnable [0x00007f22439e2000]
java.lang.Thread.State: RUNNABLE
at java.lang.Thread.yield(java.base@11/Native Method)
at test.ThreadStateTest$1.run(modules/ThreadStateTest.java:13)
"TEST_Thread.sleep(n)" #13 ... waiting on condition [0x00007f22438e1000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(java.base@11/Native Method)
at test.ThreadStateTest$2.run(modules/ThreadStateTest.java:22)
"TEST_Object.wait()" #14 ... in Object.wait() [0x00007f22437e0000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(java.base@11/Native Method)
- waiting on <0x0000000718aeb7a0> (a test.ThreadStateTest$3)
at java.lang.Object.wait(java.base@11/Object.java:328)
at test.ThreadStateTest$3.run(modules/ThreadStateTest.java:34)
- waiting to re-lock in wait() <...> (a test.ThreadStateTest$3)
"TEST_Object.wait(n)" #15 ... in Object.wait() [0x00007f22436df000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(java.base@11/Native Method)
- waiting on <0x0000000718aec768> (a test.ThreadStateTest$4)
at test.ThreadStateTest$4.run(modules/ThreadStateTest.java:47)
- waiting to re-lock in wait() <...> (a test.ThreadStateTest$4)
"TEST_LockSupport.park()" #16 ... waiting on condition [0x00007f22435de000]
java.lang.Thread.State: WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11/Native Method)
at java.util.concurrent.locks.LockSupport.park(...)
at test.ThreadStateTest$5.run(modules/ThreadStateTest.java:58)
"TEST_LockSupport.parkNanos(n)" #17 ... waiting on condition [...]
java.lang.Thread.State: TIMED_WAITING (parking)
at jdk.internal.misc.Unsafe.park(java.base@11/Native Method)
at java.util.concurrent.locks.LockSupport.parkNanos(...)
at test.ThreadStateTest$6.run(modules/ThreadStateTest.java:65)
"TEST_synchronized" #18 ... waiting for monitor entry [0x00007f22433dc000]
java.lang.Thread.State: BLOCKED (on object monitor)
at test.ThreadStateTest$7.run(modules/ThreadStateTest.java:74)
- waiting to lock <...> (a java.lang.Class for java.lang.Object)
由上我们可以看到,Java线程的状态可以为RUNNABLE、WAITING、TIMED_WAITING和BLOCKED等,而通过其堆栈信息,我们又可以大致推测出是何种操作导致的这种状态。
不过,细心的朋友在看上面的堆栈信息时肯定会有很多困惑,比如,同样是调用了Object.wait方法,为什么线程#14进入的是WAITING状态,而线程#15进入的是TIMED_WAITING状态呢?
下面我们还是通过源码角度对此做个全面的分析。
首先,找到jstack命令对应的JVM源码
C 文件src/hotspot/share/services/attachListener.cpp
代码语言:javascript复制static jint thread_dump(AttachOperation* op, outputStream* out) {
...
// thread stacks
VM_PrintThreads op1(out, print_concurrent_locks, print_extended_info);
VMThread::execute(&op1);
// JNI global handles
VM_PrintJNI op2(out);
VMThread::execute(&op2);
// Deadlock detection
VM_FindDeadlocks op3(out);
VMThread::execute(&op3);
return JNI_OK;
}
因为我们关心的是 thread stacks 部分,所以看下VM_PrintThreads对应的操作
C 文件src/hotspot/share/runtime/vm_operations.cpp
代码语言:javascript复制void VM_PrintThreads::doit() {
Threads::print_on(_out, true, false, _print_concurrent_locks, _print_extended_info);
}
再看下Threads::print_on方法
C 文件src/hotspot/share/runtime/thread.cpp
代码语言:javascript复制// Threads::print_on() is called at safepoint by VM_PrintThreads operation.
void Threads::print_on(outputStream* st, bool print_stacks,
bool internal_format, bool print_concurrent_locks,
bool print_extended_info) {
...
ALL_JAVA_THREADS(p) {
ResourceMark rm;
p->print_on(st, print_extended_info);
if (print_stacks) {
if (internal_format) {
p->trace_stack();
} else {
p->print_stack_on(st);
}
}
...
}
...
}
重点看下Java线程的print_on方法
C 文件src/hotspot/share/runtime/thread.cpp
代码语言:javascript复制// Called by Threads::print() for VM_PrintThreads operation
void JavaThread::print_on(outputStream *st, bool print_extended_info) const {
...
st->print_raw(get_thread_name());
...
if (thread_oop != NULL) {
st->print_cr(" java.lang.Thread.State: %s", java_lang_Thread::thread_status_name(thread_oop));
}
...
}
在这里我们找到了输出线程状态的地方。我们再看下java_lang_Thread::thread_status_name方法
C 文件src/hotspot/share/classfile/javaClasses.cpp
代码语言:javascript复制const char* java_lang_Thread::thread_status_name(oop java_thread) {
assert(_thread_status_offset != 0, "Must have thread status");
ThreadStatus status = (java_lang_Thread::ThreadStatus)java_thread->int_field(_thread_status_offset);
switch (status) {
case NEW : return "NEW";
case RUNNABLE : return "RUNNABLE";
case SLEEPING : return "TIMED_WAITING (sleeping)";
case IN_OBJECT_WAIT : return "WAITING (on object monitor)";
case IN_OBJECT_WAIT_TIMED : return "TIMED_WAITING (on object monitor)";
case PARKED : return "WAITING (parking)";
case PARKED_TIMED : return "TIMED_WAITING (parking)";
case BLOCKED_ON_MONITOR_ENTER : return "BLOCKED (on object monitor)";
case TERMINATED : return "TERMINATED";
default : return "UNKNOWN";
};
}
在该方法里,我们可以看到Java线程的所有可能状态,以及各种状态对应到jstack里会输出的名字。
那这些状态又是在哪里设置的呢?
JVM中有一个C 类叫JavaThreadStatusChanger,该类及其子类就是用来修改Java线程状态的,我们看下都有哪些子类
代码语言:javascript复制File: src/hotspot/share/services/threadService.hpp
469:34:class JavaThreadInObjectWaitState : public JavaThreadStatusChanger {
498:28:class JavaThreadParkedState : public JavaThreadStatusChanger {
527:43:class JavaThreadBlockedOnMonitorEnterState : public JavaThreadStatusChanger {
584:27:class JavaThreadSleepState : public JavaThreadStatusChanger {
由上我们可以看到,一共有四个子类负责修改Java线程的状态。
但又是什么操作导致这些类对Java线程的状态进行修改的呢?下面我们以JavaThreadInObjectWaitState类举例说明下。首先看下这个类
C 文件src/hotspot/share/services/threadService.hpp
代码语言:javascript复制// Change status to waiting on an object (timed or indefinite)
class JavaThreadInObjectWaitState : public JavaThreadStatusChanger {
...
public:
JavaThreadInObjectWaitState(JavaThread *java_thread, bool timed) :
JavaThreadStatusChanger(java_thread,
timed ? java_lang_Thread::IN_OBJECT_WAIT_TIMED : java_lang_Thread::IN_OBJECT_WAIT) {
...
}
...
};
由上可见,该类会根据timed参数来决定是把Java线程修改为IN_OBJECT_WAIT_TIMED状态还是IN_OBJECT_WAIT状态。我们再来看下这个类是在哪里创建的,以及timed参数又是怎么传入的
C 文件src/hotspot/share/prims/jvm.cpp
代码语言:javascript复制JVM_ENTRY(void, JVM_MonitorWait(JNIEnv* env, jobject handle, jlong ms))
...
JavaThreadInObjectWaitState jtiows(thread, ms != 0);
...
ObjectSynchronizer::wait(obj, ms, CHECK);
JVM_END
由上可见,JavaThreadInObjectWaitState类的是由JVM_MonitorWait方法创建的,且timed参数是由ms是否等于0决定的。如果ms等于0,Java线程就会被JavaThreadInObjectWaitState类修改为IN_OBJECT_WAIT状态,如果不等于0,就会被修改为IN_OBJECT_WAIT_TIMED状态。
我们再来看下是谁调用的JVM_MonitorWait方法。
C文件src/java.base/share/native/libjava/Object.c
代码语言:javascript复制static JNINativeMethod methods[] = {
...
{"wait", "(J)V", (void *)&JVM_MonitorWait},
{"notify", "()V", (void *)&JVM_MonitorNotify},
{"notifyAll", "()V", (void *)&JVM_MonitorNotifyAll},
...
};
由上可以看到,是Java类java.lang.Object中的Object.wait这个native方法。
至此,我们就明白了,当我们调用Object.wait方法时,会切换Java线程的状态。如果调用该方法时传入的参数为0,Java线程就会被切换成IN_OBJECT_WAIT状态,对应jstack的输出为”WAITING (on object monitor)”。如果传入的参数大于0,Java线程就会被切换成IN_OBJECT_WAIT_TIMED状态,对应的jstack输出就是 “TIMED_WAITING (on object monitor)”。
其他三个子类也是类似,在此就不一一赘述了。
下面我们总结下,jstack命令可能输出线程状态以及导致这种状态的操作是什么。
jstack输出 | 对应的操作 ------------------------------------------------------------------------- NEW | 创建Thread对象 RUNNABLE | 调用Thread.start方法 TERMINATED | 销毁Thread对象 TIMED_WAITING (sleeping) | 调用Thread.sleep方法 WAITING (on object monitor) | 调用Object.wait方法,参数为0 TIMED_WAITING (on object monitor) | 调用Object.wait方法,参数大于0 WAITING (parking) | 调用Unsafe.park方法,参数为0 | (通常由LockSupport.park系列方法触发) TIMED_WAITING (parking) | 调用Unsafe.park方法,参数大于0 | (通常由LockSupport.park系列方法触发) BLOCKED (on object monitor) | 等待进入synchronize代码块 | (其他线程正在执行该代码块)
其实Java类java.lang.Thread.State的Javadoc对此也有较为详细的描述,只是其状态和jstack中的状态不是一一对应的,所以我们一开始并没有提到,这里也顺便看下吧。
代码语言:javascript复制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 {@code Object.wait()}
* on an object is waiting for another thread to call
* {@code Object.notify()} or {@code Object.notifyAll()} on
* that object. A thread that has called {@code Thread.join()}
* 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;
}
最后,附上本文中用于jstack命令的Java测试代码
代码语言:javascript复制// RUNNABLE
new Thread("TEST_while(true)") {
@Override
public void run() {
while (true) {
Thread.yield();
}
}
}.start();
// TIMED_WAITING (sleeping)
new Thread("TEST_Thread.sleep(n)") {
@Override
public void run() {
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
// WAITING (on object monitor)
new Thread("TEST_Object.wait()") {
@Override
public void run() {
try {
synchronized (this) {
wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
// TIMED_WAITING (on object monitor)
new Thread("TEST_Object.wait(n)") {
@Override
public void run() {
try {
synchronized (this) {
wait(Integer.MAX_VALUE);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
// WAITING (parking)
new Thread("TEST_LockSupport.park()") {
@Override
public void run() {
LockSupport.park();
}
}.start();
// TIMED_WAITING (parking)
new Thread("TEST_LockSupport.parkNanos(n)") {
@Override
public void run() {
LockSupport.parkNanos(Long.MAX_VALUE);
}
}.start();
// BLOCKED (on object monitor)
synchronized (Object.class) {
new Thread("TEST_synchronized") {
@Override
public void run() {
synchronized (Object.class) {
System.out.println("Should not reach here!");
}
}
}.start();
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}