首页 > 编程语言 >从Thread.start入手Hotspot源码

从Thread.start入手Hotspot源码

时间:2022-08-14 22:28:37浏览次数:56  
标签:java thread JavaThread Hotspot start 源码 线程 pthread void

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;
  }

  // 清理工作
}

标签:java,thread,JavaThread,Hotspot,start,源码,线程,pthread,void
From: https://www.cnblogs.com/kendoziyu/p/16585069.html

相关文章

  • JDK数组阻塞队列源码深入剖析
    JDK数组阻塞队列源码深入剖析前言在前面一篇文章从零开始自己动手写阻塞队列当中我们仔细介绍了阻塞队列提供给我们的功能,以及他的实现原理,并且基于谈到的内容我们自己实......
  • Vue2.x+Node.js拼多多商城项目实战课程学习有感(附源码)
    本人计算机本科毕业,本来毕业后挺迷茫的,听学长们说现在前端比较吃香,想着自己自学前端去找工作,于是网上各种找学习课程或者购买一些学习资料在家自学,据学长们所说,能自学会的......
  • Sentinel源码分析-滑动窗口统计原理
    滑动窗口技术是Sentinel比较关键的核心技术,主要用于数据统计通过分析StatisticSlot来慢慢引出这个概念@Overridepublicvoidentry(Contextcontext,ResourceWrap......
  • Sentinel 源码分析- 熔断降级原理分析
    直接从Sentinel源码demoExceptionRatioCircuitBreakerDemo看起直接看他的main函数publicstaticvoidmain(String[]args)throwsException{initDegradeRu......
  • gin 框架源码分析
    官方文档示例packagemainimport"github.com/gin-gonic/gin"funcmain(){ r:=gin.Default() r.GET("/ping",func(c*gin.Context){ c.JSON(200,gin.H{ ......
  • Sentinel 源码分析-限流原理
    1.gitclonesenetinel源码到本地,切换到release1.8分支2.找到FlowQpsDemo.java,根据sentinel自带的案例来学习sentinel的原理3.先看main方法publicstaticvoid......