目录
1.1既然是thread 类,我们先看到 thread.c 中找
1.2既然是 jvm的,就在jvm.cpp上打断点了 2817行
4可以看出 这里是javaThread的一个构造方法 ,我们进去 thread.cpp 1570 行
5java_start 方法是在哪里呢? os_linux.cpp 806行,我们看看这个方法到底在干嘛
6还记得创建线程是哪里吗 ?jvm.cpp 2851 行,我们接着往下走 到 2884 行
7此时java_start 方法继续执行 os_linux.cpp 中判断线程状态已经是running了,所以放行。860行
8跳转到 thread.cpp 1679行 真正执行run方法的回调以及线程销毁
1为什么要看这个源码
-
熟悉源码,了解底层 知彼知己。平时我们就写start方法 反正就会调用run方法。不可靠源码总觉得模糊,不可靠。
-
作为一个线程的启动过程,其实也是main线程启动流程的一部分,因为main本身也是线程嘛,上次课说过main的启动流程,再次梳理下线程的流程也算是巩固下知识。
2. debug 步骤
1.1既然是thread 类,我们先看到 thread.c 中找
1.2既然是 jvm的,就在jvm.cpp上打断点了 2817行
-
3我们跳入到 2851行
native_thread = new JavaThread(&thread_entry, sz); //创建一个对应的内核线程,这里注意thread_entry,后续会执行这个方法
-
4可以看出 这里是javaThread的一个构造方法 ,我们进去 thread.cpp 1570 行
set_entry_point(entry_point); //这里要注意:run方法回调入口点在这里设置进去了
1576行,创建原生线程
我们进入看看发生了什么,跳入到 os_linux.cpp 865行
// Allocate the OSThread object
OSThread* osthread = new OSThread(NULL, NULL); //OSThread是java线程和内核线程直接的桥梁
if (osthread == NULL) {
return false;
}
// set the correct thread state
osthread->set_thread_type(thr_type);
// Initial state is ALLOCATED but not INITIALIZED
osthread->set_state(ALLOCATED);
thread->set_osthread(osthread); //先将osthread与java thread关联
跳转到 934行 真正的 创建内核线程,并等待java_start 方法
int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread); //创建对应的内核线程,并启动线程(执行java_start方法,并阻塞)
-
5java_start 方法是在哪里呢? os_linux.cpp 806行,我们看看这个方法到底在干嘛
我们跳转到854行
// wait until os::start_thread()
while (osthread->get_state() == INITIALIZED) { //这里会循环阻塞,一直等到线程状态为runnable才往下执行
sync->wait(Mutex::_no_safepoint_check_flag);
}
也就是说 java_start 方法一直在while循环 ,如果线程状态一直是 INITIALIZED ,就一直while循环 不往下执行。
-
6还记得创建线程是哪里吗 ?jvm.cpp 2851 行,我们接着往下走 到 2884 行
Thread::start(native_thread); //启动线程,主要是设置状态为RUNNABLE(java_start方法中会感知,然后initialized状态修改为RUNNABLE,流程继续往下调用run方法)
点进入到 thread.cpp 464行
继续跟进到 os_linux.cpp 863
osthread->set_state(RUNNABLE); //这里设置线程状态为RUNNABLE状态,很重要,设置完之后在java_start方法中感知
-
7此时java_start 方法继续执行 os_linux.cpp 中判断线程状态已经是running了,所以放行。860行
thread->run();
-
8跳转到 thread.cpp 1679行 真正执行run方法的回调以及线程销毁
thread_main_inner(); //这个方法很重要,会调线程入口.执行具体的run方法并在执行完成销毁当前实例
继续到 1699行 回调run方法
this->entry_point()(this, this); //回调线程run入口。执行entry_point函数,就是执行Thread的run方法
OK! 此时 流程已经全部走完了。 还是比较简单的吧。
总结下:
创建个线程,并发run回调入口设置进去,然后创建个内核线程,并等待java_start 方法的完成,java_start 方法判断线程状态如果是 初始化 就一直while循环,直到线程状态改变就继续执行 最后回调run方法。