Java 中经常会遇到要获取当前线程的情况,这时一般我们就会通过 Thread.currentThread()
来获取,接下去就看看执行该语句在 JVM 中做了什么吧。
以下是一个简单的例子,获取当前线程并打印线程名称,输出是"main",即主线程。
public class CurrentThreadTest { public static void main(String[] args) { Thread t = Thread.currentThread(); System.out.println(t.getName()); } }
在 Thread 类中, currentThread
是一个静态且本地方法。
public static native Thread currentThread();
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
主要逻辑:
#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();
-------------推荐阅读------------
我的2017文章汇总——机器学习篇
我的2017文章汇总——Java及中间件
我的2017文章汇总——深度学习篇
我的2017文章汇总——JDK源码篇
我的2017文章汇总——自然语言处理篇
我的2017文章汇总——Java并发篇
跟我交流,向我提问:
公众号的菜单已分为“读书总结”、“分布式”、“机器学习”、“深度学习”、“NLP”、“Java深度”、“Java并发核心”、“JDK源码”、“Tomcat内核”等,可能有一款适合你的胃口。
为什么写《Tomcat内核设计剖析》
欢迎关注: