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

前言

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

原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/256009.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
投稿專員的頭像投稿專員
上一篇 2024-12-15 12:32
下一篇 2024-12-15 12:32

相關推薦

發表回復

登錄後才能評論