【学习笔记】从Thread.start追踪Hotspot源码

native start0追踪到hotspot源码中

private void native start0();

native的原理是调用 JNI,而 Hotspot 源码的惯例则是,通常一个 Xxx.java 对应一个 Xxx.c,

以下举三个例子:

Java 类 相对于OpenJDK源码的路径
java.lang.Thread jdk/src/share/native/java/lang/Thread.c
java.lang.String jdk/src/share/native/java/lang/String.c
java.lang.System jdk/src/share/native/java/lang/System.c

所以 native start0 对应调用是以下 JNINativeMethod 数组中第一个元素的 JVM_StartThread 函数。

static JNINativeMethod methods[] = {
{"start0",           "()V",        (void *)&JVM_StartThread},...}

JVM_ 开头的函数,可以到 jvm.cpp 中寻找实现。(即 hotspot/src/share/vm/prims/jvm.cpp

JVM_StartThread 中重要的代码

1. 创建C++层面的JavaThread

JavaThread-OSThread-pthread
JavaThread 和 OSThread 之间的关系?
JavaThread 的父类成员变量 _osthread 保存着对应的 OSThread 对象。

OSThread 和 pthread(Linux 操作系统线程)之间的关系?
OSThread 的成员变量 _pthread_id 保存着 pthread_create 的返回值,所有 Linux pthread 相关 API 都需要用到 pthread_t 对象。

因此,native_thread = new JavaThread(&thread_entry, sz); 创建C++层面的JavaThread,构建起 JavaThread对象 与 OSThread对象,OSThread对象与 OS线程对象(例如 Linux中的 pthread)之间的关联。

2. JavaThread的prepare方法

void JavaThread::prepare(jobject jni_thread, ThreadPriority prio) 
  1. 为Java的Thread对象对应C++的oop对象设置C++的JavaThread对象。即构建 Java 的Thread对象与JavaThread对象的关联;
  2. 把创建的所有线程放入到一个容器中去。容器的作用是在 GC 的 STW 过程中,遍历到当前进程的所有线程;

3. Thread::start(native_thread)

os线程函数java_start中怎么执行的Java的线程的run方法?

static void *java_start(Thread *thread) {}

静态方法 java_start 的函数体内最后一行调用 thread->run();

void JavaThread::run() {}

JavaThread类成员函数run的函数体内最后一行调用 thread_main_inner()

void JavaThread::thread_main_inner() {}

JavaThread类成员函数thread_main_inner内有一行调用 this->entry_point()(this, this);

entry_point其实执行是的静态函数 thread_entry:

static void thread_entry(JavaThread* thread, TRAPS) {
  HandleMark hm(THREAD);
  Handle obj(THREAD, thread->threadObj());
  JavaValue result(T_VOID);
  JavaCalls::call_virtual(&result,
                          obj,
                          KlassHandle(THREAD, SystemDictionary::Thread_klass()),
                          vmSymbols::run_method_name(),
                          vmSymbols::void_method_signature(),
                          THREAD);
}

JVM是如何执行Java的run方法的?

继续跟踪 call_virtual 函数到该位置:

void JavaCalls::call(JavaValue* result, methodHandle method, JavaCallArguments* args, TRAPS) {
   // JavaCalls::call_helper 也是一个成员函数    
    os::os_exception_wrapper(call_helper, result, &method, args, THREAD);
}

函数 os::os_exception_wrapper 实际会调用 call_helper 函数,而 call_helper 函数中有一处调用 call_stub 的代码:

StubRoutines::call_stub()(
  (address)&link,
  // (intptr_t*)&(result->_value), // see NOTE above (compiler problem)
  result_val_address,          // see NOTE above (compiler problem)
  result_type,
  method(),
  entry_point,
  args->parameters(),
  args->size_of_parameters(),
  CHECK
);

这段 call_stub 的调用,是 JVM 和 Java 的分水岭,越过他就进入到 Java 的世界中。

JVM_StartThread运行在哪个线程中?

JVM_StartThread 运行在 main 线程中。

main 线程的创建代码在

// 当前函数运行在“主控线程”中
int ContinueInNewThread0(int (JNICALL *continuation)(void *), jlong stack_size, void * args) {
  // 创建pthread前的准备工作
  int rslt;
  pthread_t tid;
  pthread_attr_t attr;
  pthread_attr_init(&attr);
  // main线程的线程属性————JOINABLE

  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 

  // 在主控线程中创建一个main线程
  if (pthread_create(&tid, &attr, (void *(*)(void*))continuation, (void*)args) == 0) {
    void * tmp;
    // 主控线程等待 main线程执行完
    pthread_join(tid, &tmp);
    rslt = (int)tmp;
  }

  // 清理工作
}
posted @   极客子羽  阅读(156)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示