正文

設置和獲取當前線程名稱(java代碼大全及詳解)

5424

前言

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();