前言
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函数里。逻辑为:
#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();