java多线程(一)
更新时间:2023年1月29日,本系列预计3篇文章,本篇文章更新60%
技术类文章欢迎勘误,勘误邮箱:report#ripic.site(#换@)
启动一个新的java线程还是比较简单的,下面代码通过Lamda表达式描述了java线程的启动方法
1 | new Thread(()->{ |
Java的线程创建和启动非常简单,但如果问一个线程是怎么启动起来的往往并不清楚,甚至不知道为什么启动时是调用start(),而不是调用run()方法呢?
下面引用一张很经典的图片,来说明一个新的java线程被创建的过程:
通过上面的图片,我们很清晰的知道:
- 线程的启动会涉及到本地方法(JNI)的调用,也就是那部分 C++ 编写的代码。
- JVM 的实现中会有不同操作系统对线程的统一处理,比如:Win、Linux、Unix。
- 线程的启动会涉及到线程的生命周期状态(RUNNABLE),以及唤醒操作,所以最终会有回调操作(也就是调用我们的 run() 方法)
因此我们应该清楚,我们在程序运行的过程中只涉及到start()方法的调用,在Thread内部由程序调用run()方法启动线程。
下面,深入源码查看一下线程的启动过程
start方法
1 | // JDK 源码 |
- 首先,start()方法是一个synchronized方法,为了避免多次调用,会进行threadStatus!=0的判断;
- start0()在后续的源码中能够发现,是一个本地方法,与JVM虚拟机息息相关;
- group.add(this)是把当前方法加入线程组。
从上面的代码可以看出start0()是新建县城的核心,下面我们继续探究
start0()本地方法
我们注意到,在public class Thread implements Runnable{}
中,存在一个静态代码块
1 | private static native void registerNatives(); |
这个方法中调用了本地方法registerNatives()
,我们先来探究这个方法的底层实现。
源码:https://github.com/openjdk/jdk/blob/master/src/java.base/share/native/libjava/Thread.c
1 | static JNINativeMethod methods[] = { |
核心代码如上,主要是“注册”了一些核心的功能性方法,start0()调用的是JVM_StartThread
,继续分析
JVM_StartThread
源码(2933行附近):https://github.com/openjdk/jdk/blob/master/src/hotspot/share/prims/jvm.cpp
1 | JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread)) |
由于源码较多,仅保留了创建线程
和启动线程
的源码,更多源码,请前往Github查看
注意到在创建线程的时候用到了thread_entry
,下面贴一下他的源码
1 | static void thread_entry(JavaThread* thread, TRAPS) { |
根据方法名可以猜测,这个方法起到了线程入口的作用,这里面包含了线程会掉函数call_virtual
,这个方法会回调JVM(通过这个方法调用JVM中的函数)。
回调中涉及到vmSymbols
方法(源码:https://github.com/openjdk/jdk/blob/master/src/hotspot/share/classfile/vmSymbols.hpp#L400)
1 |
|
这里就是调用java中的run()方法,现在整个调用过程逐渐清晰起来了。下面我们继续循着这个调用过程剖析调用过程。
创建线程
JavaThread
1 | native_thread = new JavaThread(&thread_entry, sz); |
源码:https://github.com/openjdk/jdk/blob/master/src/hotspot/share/runtime/javaThread.cpp#L592
1 | JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz) : JavaThread() { |
- ThreadFunction entry_point,就是我们上面的 thread_entry 方法。
- size_t stack_sz,表示进程中已有的线程个数。这两个参数(thr_type,stack_sz),都会传递给 os::create_thread 方法,用于创建线程使用。
os::create_thread
这里以linux为例
源码:https://github.com/openjdk/jdk/blob/master/src/hotspot/os/linux/os_linux.cpp#L816
1 | bool os::create_thread(Thread* thread, ThreadType thr_type, |
- osthread->set_state(ALLOCATED),初始化已分配的状态,但此时并没有初始化。
- pthread_create unix系统线程创建函数
- thread_native_entry(旧:java_start)实际线程创建方法(Thread start routine for all newly created threads)
thread_native_entry
1 | static void *thread_native_entry(Thread *thread) { |
osthread->set_state(INITIALIZED);
:JVM 设置线程状态,INITIALIZED 初始化完成。sync->notify_all()
:唤醒线程osthread->get_state() == INITIALIZED
:循环等待条件thread->call_run();
:是等待线程唤醒后,也就是状态变更后,才能执行到。这在我们的线程执行UML图中,也有所体现
启动线程
waiting
等地更新