前言
Java 中經常會遇到要獲取當前線程的情況,這時一般我們就會通過Thread.currentThread()來獲取,接下去就看看執行該語句在 JVM 中做了什么吧。
簡單例子
以下是一個簡單的例子,獲取當前線程并打印線程名稱,輸出是”main”,即主線程。
public?class?CurrentThreadTest?{ ?public?static?void?main(String[]?args)?{ ?Thread?t?=?Thread.currentThread(); ?System.out.println(t.getName()); ?} }
currentThread方法
在 Thread 類中,currentThread是一個靜態且本地方法。
public?static?native?Thread?currentThread();
Thread.c
Java 層聲明的本地方法對應實現在 Thread.c 中,currentThread是一個注冊到 JVM 中的方法,它與 JVM 中的JVM_CurrentThread函數綁定了,所以實現邏輯在JVM_CurrentThread函數里。邏輯為:
-
JVMWrapper(“JVM_CurrentThread”)用于調試。
-
通過thread->threadObj()獲取 oop,這里的 thread 是在JNI_ENTRY宏中獲取到的,詳細情況可參考后面的JNI_ENTRY和JNI_END宏。
-
調用JNIHandles::make_local函數
#define?THD?"Ljava/lang/Thread;" static?JNINativeMethod?methods[]?=?{ ?... ?{"currentThread",?"()"?THD,?(void?*)&JVM_CurrentThread}, ?... }; JVM_ENTRY(jobject,?JVM_CurrentThread(JNIEnv*?env,?jclass?threadClass)) ?JVMWrapper("JVM_CurrentThread"); ?oop?jthread?=?thread->threadObj(); ?assert?(thread?!=?NULL,?"no?current?thread!"); ?return?JNIHandles::make_local(env,?jthread); JVM_END
make_local函數中主要看
thread_from_jni_environment函數,它用于獲取當前線程,它的邏輯為JavaThread *thread_from_jni_env = (JavaThread*)((intptr_t)env – in_bytes(jni_environment_offset()));,即直接通過地址偏移來做減法計算得到JavaThread*,這是因為 JavaThread 對象包含了 JNIEnv 對象屬性,所以可以通過JNIEnv*與偏移做減法來算出JavaThread*。最后還要檢查線程是否已經終止狀態,沒有終止才返回該線程對象。
獲取到JavaThread*對象后,分配句柄并將 oop 賦給句柄,并且轉成 Java 層的對象 jobject。
jobject?JNIHandles::make_local(JNIEnv*?env,?oop?obj)?{ ?if?(obj?==?NULL)?{ ?return?NULL;? ?}?else?{ ?JavaThread*?thread?=?JavaThread::thread_from_jni_environment(env); ?assert(Universe::heap()->is_in_reserved(obj),?"sanity?check"); ?return?thread->active_handles()->allocate_handle(obj); ?} } static?JavaThread*?thread_from_jni_environment(JNIEnv*?env)?{ ?JavaThread?*thread_from_jni_env?=?(JavaThread*)((intptr_t)env?-?in_bytes(jni_environment_offset())); ?if?(thread_from_jni_env->is_terminated())?{ ?thread_from_jni_env->block_if_vm_exited(); ?return?NULL; ?}?else?{ ?return?thread_from_jni_env; ?} ?}
`JNI_ENTRY`和`JNI_END`宏
這兩個宏將共同的部分都抽離出來了。其中JNI_END比較簡單,就兩個結束大括號。
#define?JNI_ENTRY(result_type,?header)?JNI_ENTRY_NO_PRESERVE(result_type,?header)?WeakPreserveExceptionMark?__wem(thread); #define?JNI_END?}?}
JNI_ENTRY主要邏輯:
-
獲取當前執行線程 JavaThread 指針對象。
-
創建 ThreadInVMfromNative 對象。
-
TRACE_CALL ,這里什么都不干。
-
創建 HandleMarkCleaner 對象。
-
將 thread 賦值給 Exceptions 中的 THREAD。
-
校驗棧對齊。
-
創建 WeakPreserveExceptionMark 對象。
#define?JNI_ENTRY_NO_PRESERVE(result_type,?header)? extern?"C"?{? ?result_type?JNICALL?header?{? ?JavaThread*?thread=JavaThread::thread_from_jni_environment(env);? ?assert(?!VerifyJNIEnvThread?||?(thread?==?Thread::current()),?"JNIEnv?is?only?valid?in?same?thread");? ?ThreadInVMfromNative?__tiv(thread);? ?debug_only(VMNativeEntryWrapper?__vew;)? ?VM_ENTRY_BASE(result_type,?header,?thread) #define?VM_ENTRY_BASE(result_type,?header,?thread)? ?TRACE_CALL(result_type,?header)? ?HandleMarkCleaner?__hm(thread);? ?Thread*?THREAD?=?thread;? ?os::verify_stack_alignment();