【Java并发】new Thread时JVM做了什么?
最近兴致勃勃捡起C++,打算深入Unix网络编程,但输出博客想从比较简单的问题入手,所以对标一下Java与C的线程创建过程,加深一下理解。(注,Linux)
Java创建线程是简单的,new Thread()
和start()
即可启动并执行线程,但由于posix提供的api还涉及不少线程属性,真实过程显然要复杂得多。可以看到前者new Thread
只是初始化属性,后者才是真正意义上调用本地接口JVM_StartThread
,创建线程。
1 | //以下函数指针均被定义在jvm.h,实现在jvm.cpp |
阅读相关JVM源码时,需要知道几个重要类的关系,下面部分实现默认os_linux.cpp。
1 | 1、JavaThread: 创建线程执行任务,持有java_lang_thread & OSThread对象,维护线程状态运行Thread.run()的地方 |
需要说的是,以下相关pthread函数均是posix标准,可自行阅读<pthread.h>文档,不多赘述。
1 | JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread)) |
我们知道pthread_create
创建线程后立刻执行线程,所以什么Thread::start
才是真正启动线程,我们需要进一步窥探。
1 | //JavaThread类定义在thread.hpp中,为Thread的子类 |
create_thread
对线程属性的设置跟日常写c++时有些不同,包括警戒线缓冲区和页面对其,一般我们并不会考虑aligned。
1 | //os_linux.cpp |
由于pthread_create
会立即执行thread_native_entry
,但又因为JavaThread被OSThread管理着,所以需要加各种排斥锁,达到二者状态同步的效果。
1 | static void *thread_native_entry(Thread *thread) { |
执行Runable之前,JVM需要给java线程分配本地缓冲区等操作(这是一个大块),这里算是到头了。
1 | void JavaThread::run() { |
下面代码不多做解释了,this->entry_point()(this, this)
等同于调用函数thread_entry
,JavaCalls
也是个大块,复杂调用java方法。
1 | void JavaThread::thread_main_inner() { |
总体来说,创建一个线程对于JVM来说还是相对费劲的,不是说性能不好,是需要做太多事。与GC息息相关的两个点就是TLAB与ThreadSafePoint,其他则是对于java程序员透明的栈空间的分配(这里指的是虚拟内存地址)、线程状态管理。