源码见:
https://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/69087d08d473/src/os/linux/vm/os_linux.cpp
主要通过pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread) , 它是unix 创建线程的方法 , linux也继承了 。调用后在linux系统中会创建一个内核级的线程 。也就是说这个时候操作系统中线程才真正地诞生
但此时线程才诞生 , 那是怎么启动的?我们回到JVM_StartThread源码中 , Thread::start(native_thread)很明显这行代码就表示启动native_thread = new JavaThread(&thread_entry, sz)创建的线程 , 我们来继续看看其源码
void Thread::start(Thread* thread) {trace("start", thread);// Start is different from resume in that its safety is guaranteed by context or// being called from a Java method synchronized on the Thread object.if (!DisableStartThread) {if (thread->is_Java_thread()) {// 设置线程状态java_lang_Thread::set_thread_status(((JavaThread*)thread)->threadObj(),java_lang_Thread::RUNNABLE);}os::start_thread(thread);}}源码:
https://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/69087d08d473/src/share/vm/runtime/thread.cpp
os::start_thread它封装了pd_start_thread(thread),执行该方法 , 操作系统会去启动指定的线程
void os::start_thread(Thread* thread) {// guard suspend/resumeMutexLockerEx ml(thread->SR_lock(), Mutex::_no_safepoint_check_flag);OSThread* osthread = thread->osthread();osthread->set_state(RUNNABLE);pd_start_thread(thread);}当操作系统的线程启动完之后 , 我们再回到pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread) , 会去java_start这个线程入口函数进行OS内核级线程的初始化 , 并开始启动JavaThread
【原来还能这么看Java线程的状态及转换】// Thread start routine for all newly created threadsstatic void *java_start(Thread *thread) {// Try to randomize the cache line index of hot stack frames.// This helps when threads of the same stack traces evict each other's// cache lines. The threads can be either from the same JVM instance, or// from different JVM instances. The benefit is especially true for// processors with hyperthreading technology.static int counter = 0;int pid = os::current_process_id();alloca(((pid ^ counter++) & 7) * 128);ThreadLocalStorage::set_thread(thread);OSThread* osthread = thread->osthread();Monitor* sync = osthread->startThread_lock();// non floating stack LinuxThreads needs extra check, see aboveif (!_thread_safety_check(thread)) {// notify parent threadMutexLockerEx ml(sync, Mutex::_no_safepoint_check_flag);osthread->set_state(ZOMBIE);sync->notify_all();return NULL;}// thread_id is kernel thread id (similar to Solaris LWP id)osthread->set_thread_id(os::Linux::gettid());if (UseNUMA) {int lgrp_id = os::numa_get_group_id();if (lgrp_id != -1) {thread->set_lgrp_id(lgrp_id);}}// initialize signal mask for this threados::Linux::hotspot_sigmask(thread);// initialize floating point control registeros::Linux::init_thread_fpu_state();// handshaking with parent thread{MutexLockerEx ml(sync, Mutex::_no_safepoint_check_flag);// notify parent threadosthread->set_state(INITIALIZED);sync->notify_all();// 等待,直到操作系统级线程全部启动while (osthread->get_state() == INITIALIZED) {sync->wait(Mutex::_no_safepoint_check_flag);}}// 开始运行JavaThread::runthread->run();return 0;}源码:
https://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/69087d08d473/src/os/linux/vm/os_linux.cpp
thread->run()其实就是JavaThread::run()也表明方法开始回调 , 从OS层方法回到JVM层方法 , 我们再来看下其实现:
// The first routine called by a new Java threadvoid JavaThread::run() {// initialize thread-local alloc buffer related fieldsthis->initialize_tlab();// used to test validitity of stack trace backsthis->record_base_of_stack_pointer();// Record real stack base and size.this->record_stack_base_and_size();// Initialize thread local storage; set before calling MutexLockerthis->initialize_thread_local_storage();this->create_stack_guard_pages();this->cache_global_variables();// Thread is now sufficient initialized to be handled by the safepoint code as being// in the VM. Change thread state from _thread_new to _thread_in_vmThreadStateTransition::transition_and_fence(this, _thread_new, _thread_in_vm);assert(JavaThread::current() == this, "sanity check");assert(!Thread::current()->owns_locks(), "sanity check");DTRACE_THREAD_PROBE(start, this);// This operation might block. We call that after all safepoint checks for a new thread has// been completed.this->set_active_handles(JNIHandleBlock::allocate_block());if (JvmtiExport::should_post_thread_life()) {JvmtiExport::post_thread_start(this);}JFR_ONLY(Jfr::on_thread_start(this);)// We call another function to do the rest so we are sure that the stack addresses used// from there will be lower than the stack base just computedthread_main_inner();//!!!注意此处方法// Note, thread is no longer valid at this point!}void JavaThread::thread_main_inner() {assert(JavaThread::current() == this, "sanity check");assert(this->threadObj() != NULL, "just checking");// Execute thread entry point unless this thread has a pending exception// or has been stopped before starting.// Note: Due to JVM_StopThread we can have pending exceptions already!if (!this->has_pending_exception() &&!java_lang_Thread::is_stillborn(this->threadObj())) {{ResourceMark rm(this);this->set_native_thread_name(this->get_thread_name());}HandleMark hm(this);this->entry_point()(this, this);//JavaThread对象中传入的entry_point为Thread对象的Thread::run方法}DTRACE_THREAD_PROBE(stop, this);this->exit(false);delete this;}
推荐阅读
- 冻虾变黑了还能吃吗
- 发型|以前的女演员是真敬业,扮丑扮到亲妈不认!哪像现在这么“敷衍”
- 陈意涵|黄晓明锤上加锤,怒揭陈意涵“双面玉女”骗局,原来杨颖真没说谎!
- 如何在夏季来临之时减掉大肚腩,最好还能拥有马甲线?
- 陈意涵|黄晓明锤上加锤,怒揭陈意涵“双面玉女”骗局,原来杨颖真没说谎
- 蜂蜜保质期一般为多长时间 蜂蜜放了五年还能吃吗
- 大米生虫还能吃吗 大米生虫子处理诀窍
- 江疏影|这一次,江疏影被扒了个底朝天!网友:没想到这么乱!
- 张静初|黄晓明锤上加锤,怒揭陈意涵“双面玉女”骗局,原来杨颖真没说谎
- ella|Ella陈嘉桦“还没这么女过”文案翻车,上次被骂道歉的还是白鹿
