jvm線程是維護(hù)了線程的狀態(tài)晦譬。new,running尤莺,waiting涂滴,timed waiting,blocked壮吩,terminated拣宏。我們通過jstack等工具查看的時候,線程狀態(tài)就是上面的一種。jvm本身是做了一種抽象,我們現(xiàn)在從一個典型的方法剔桨,來跟蹤查看一下jvm內(nèi)部又是怎么做狀態(tài)變化的。
sleep方法入手
public static native void sleep(long millis) throws InterruptedException;
sleep是一個native 方法脚猾,我們通過jvm原來來進(jìn)行跟著(源碼來自openjdk11)提鸟。
根據(jù)jni的規(guī)范赡鲜,我們通過包名或者是jni的注冊方式找到了對應(yīng)的聲明。
static JNINativeMethod methods[] = {
{"start0", "()V", (void *)&JVM_StartThread},
{"stop0", "(" OBJ ")V", (void *)&JVM_StopThread},
{"isAlive", "()Z", (void *)&JVM_IsThreadAlive},
{"suspend0", "()V", (void *)&JVM_SuspendThread},
{"resume0", "()V", (void *)&JVM_ResumeThread},
{"setPriority0", "(I)V", (void *)&JVM_SetThreadPriority},
{"yield", "()V", (void *)&JVM_Yield},
{"sleep", "(J)V", (void *)&JVM_Sleep},
{"currentThread", "()" THD, (void *)&JVM_CurrentThread},
{"countStackFrames", "()I", (void *)&JVM_CountStackFrames},
{"interrupt0", "()V", (void *)&JVM_Interrupt},
{"isInterrupted", "(Z)Z", (void *)&JVM_IsInterrupted},
{"holdsLock", "(" OBJ ")Z", (void *)&JVM_HoldsLock},
{"getThreads", "()[" THD, (void *)&JVM_GetAllThreads},
{"dumpThreads", "([" THD ")[[" STE, (void *)&JVM_DumpThreads},
{"setNativeName", "(" STR ")V", (void *)&JVM_SetNativeThreadName},
};
接下來我們要跟蹤的就是JVM_Sleep了。
我們一點一點來解析這個方法诽俯。
首先這里有宏定義。
JVM_ENTRY(void, JVM_Sleep(JNIEnv* env, jclass threadClass, jlong millis))
我們展開JVM_ENTRY浪讳。
#define JVM_ENTRY(result_type, header) \
extern "C" { \
result_type JNICALL header { \
JavaThread* thread=JavaThread::thread_from_jni_environment(env); \
ThreadInVMfromNative __tiv(thread); \
debug_only(VMNativeEntryWrapper __vew;) \
VM_ENTRY_BASE(result_type, header, thread)
在ThreadInVMfromNative中川抡,發(fā)生了一次線程狀態(tài)的變更楔脯。
class ThreadInVMfromNative : public ThreadStateTransition {
public:
ThreadInVMfromNative(JavaThread* thread) : ThreadStateTransition(thread) {
trans_from_native(_thread_in_vm);
}
~ThreadInVMfromNative() {
trans_and_fence(_thread_in_vm, _thread_in_native);
}
};
在構(gòu)造方法中把JavaThread的thread->thread_state()狀態(tài)變?yōu)榱薩thread_in_vm。在析構(gòu)函數(shù)中把狀態(tài)改成了_thread_in_native。這里的__tiv是一個本地對象,只有在棧銷毀的時候才會觸發(fā)析構(gòu)想许,也就是說這里的轉(zhuǎn)為_thread_in_native只不過是一瞬間的事情违诗。
展開頭結(jié)束后,我們再繼續(xù)往后觀察。
JavaThreadSleepState jtss(thread);
在這個構(gòu)造方法中润努。把java_thread->threadObj()的狀態(tài)變?yōu)榱薺ava_lang_Thread::SLEEPING
static void set_thread_status(JavaThread* java_thread,
java_lang_Thread::ThreadStatus state) {
java_lang_Thread::set_thread_status(java_thread->threadObj(), state);
}
這里對應(yīng)的就是java的線程的狀態(tài)了。
在往下走就直接設(shè)置thread->osthread()的狀態(tài)為sleep。
ThreadState old_state = thread->osthread()->get_state();
thread->osthread()->set_state(SLEEPING);
狀態(tài)到這里全部設(shè)置完成敛助。
狀態(tài)梳理
通過上面的代碼纱昧,我們可以發(fā)現(xiàn)最核心的就是JavaThread的這個對象加匈,他本身代表的jvm中的線程狀態(tài)。會標(biāo)識線程是在vm還是線程是在java或者在native猫牡。具體的狀態(tài)如下
enum JavaThreadState {
_thread_uninitialized = 0, // should never happen (missing initialization)
_thread_new = 2, // just starting up, i.e., in process of being initialized
_thread_new_trans = 3, // corresponding transition state (not used, included for completness)
_thread_in_native = 4, // running in native code
_thread_in_native_trans = 5, // corresponding transition state
_thread_in_vm = 6, // running in VM
_thread_in_vm_trans = 7, // corresponding transition state
_thread_in_Java = 8, // running in Java or in stub code
_thread_in_Java_trans = 9, // corresponding transition state (not used, included for completness)
_thread_blocked = 10, // blocked in vm
_thread_blocked_trans = 11, // corresponding transition state
_thread_max_state = 12 // maximum thread state+1 - used for statistics allocation
};
這個類同時那種java線程狀態(tài)的引用。就是java_thread->threadObj()千元。這個對應(yīng)的是java的線程狀態(tài)幸海,這個也是我們jstack看到的狀態(tài)婉陷。
"main" #1 prio=5 os_prio=31 tid=0x00007fee9b809000 nid=0xe03 waiting on condition [0x0000700008d65000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at com.company.Sleep.main(Sleep.java:7)
為什么輸出的是timed_waiting(sleep),這個主要是因為格式化輸出的原因。
if(status == THREAD_STATUS_NEW){
return "NEW";
}else if(status == THREAD_STATUS_RUNNABLE){
return "RUNNABLE";
}else if(status == THREAD_STATUS_SLEEPING){
return "TIMED_WAITING (sleeping)";
}else if(status == THREAD_STATUS_IN_OBJECT_WAIT){
return "WAITING (on object monitor)";
}else if(status == THREAD_STATUS_IN_OBJECT_WAIT_TIMED){
return "TIMED_WAITING (on object monitor)";
}else if(status == THREAD_STATUS_PARKED){
return "WAITING (parking)";
}else if(status == THREAD_STATUS_PARKED_TIMED){
return "TIMED_WAITING (parking)";
}else if(status == THREAD_STATUS_BLOCKED_ON_MONITOR_ENTER){
return "BLOCKED (on object monitor)";
}else if(status == THREAD_STATUS_TERMINATED){
return "TERMINATED";
}
return "UNKNOWN";
}
在狀態(tài)格式化的時候,把sleeping的歸類成為TIMED_WAITING (sleeping)男韧。
于此同時Java Thread還拿著系統(tǒng)的線程thread->osthread()况既。
小結(jié)
jvm中起碼有三種狀態(tài)的變化,一種是代表的java規(guī)范中的線程狀態(tài)(java_thread->threadObj())憨颠,一種是表示的jvm代理的系統(tǒng)線程的狀態(tài)(thread->osthread())胳徽,同時還有jvm線程在做轉(zhuǎn)換的一種狀態(tài),是vm自己的狀態(tài)表示爽彤。
歡迎關(guān)注公眾號:肥宅英短