今天来看下HotSpotVM在Linux下的线程模型。

Thread.start

HotSpot Runtime Overview 中说道,

There are two basic ways for a thread to be introduced into the VM: execution of Java code that calls start() on a java.lang.Thread object; or attaching an existing native thread to the VM using JNI.

Thread.start会调用native方法,start0之前介绍过怎么找到这个native方法的实现,在Thread.c中,

static JNINativeMethod methods[] = {
{"start0", "()V", (void *)&JVM_StartThread},
{"stop0", "(" OBJ ")V", (void *)&JVM_StopThread},
{"isAlive", "()Z", (void *)&JVM_IsThreadAlive},
{"suspend0", "()V", (void *)&JVM_SuspendThread},
{"resume0", "()V", (void *)&JVM_ResumeThread},
{"setPriority0", "(I)V", (void *)&JVM_SetThreadPriority},
{"yield", "()V", (void *)&JVM_Yield},
{"sleep", "(J)V", (void *)&JVM_Sleep},
{"currentThread", "()" THD, (void *)&JVM_CurrentThread},
{"countStackFrames", "()I", (void *)&JVM_CountStackFrames},
{"interrupt0", "()V", (void *)&JVM_Interrupt},
{"isInterrupted", "(Z)Z", (void *)&JVM_IsInterrupted},
{"holdsLock", "(" OBJ ")Z", (void *)&JVM_HoldsLock},
{"getThreads", "()[" THD, (void *)&JVM_GetAllThreads},
{"dumpThreads", "([" THD ")[[" STE, (void *)&JVM_DumpThreads},
{"setNativeName", "(" STR ")V", (void *)&JVM_SetNativeThreadName},
};

JVM_StartThread的定义在jvm.h

JNIEXPORT void JNICALL
JVM_StartThread(JNIEnv *env, jobject thread);

详细实如今jvm.cpp

读源代码之前能够參考这里先看下java.lang.ThreadJavaThreadOSThread它们之间的关系。

JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread))
JVMWrapper("JVM_StartThread");
JavaThread *native_thread = NULL; // We cannot hold the Threads_lock when we throw an exception,
// due to rank ordering issues. Example: we might need to grab the
// Heap_lock while we construct the exception.
bool throw_illegal_thread_state = false; // We must release the Threads_lock before we can post a jvmti event
// in Thread::start.
{
// Ensure that the C++ Thread and OSThread structures aren't freed before
// we operate.
MutexLocker mu(Threads_lock); // Since JDK 5 the java.lang.Thread threadStatus is used to prevent
// re-starting an already started thread, so we should usually find
// that the JavaThread is null. However for a JNI attached thread
// there is a small window between the Thread object being created
// (with its JavaThread set) and the update to its threadStatus, so we
// have to check for this
if (java_lang_Thread::thread(JNIHandles::resolve_non_null(jthread)) != NULL) {
throw_illegal_thread_state = true;
} else {
// We could also check the stillborn flag to see if this thread was already stopped, but
// for historical reasons we let the thread detect that itself when it starts running jlong size =
java_lang_Thread::stackSize(JNIHandles::resolve_non_null(jthread));
// Allocate the C++ Thread structure and create the native thread. The
// stack size retrieved from java is signed, but the constructor takes
// size_t (an unsigned type), so avoid passing negative values which would
// result in really large stacks.
size_t sz = size > 0 ? (size_t) size : 0; //////////////////////////////////////////////////
// 1. 创建与java.lang.Thread相应的JavaThread
//////////////////////////////////////////////////
native_thread = new JavaThread(&thread_entry, sz); // At this point it may be possible that no osthread was created for the
// JavaThread due to lack of memory. Check for this situation and throw
// an exception if necessary. Eventually we may want to change this so
// that we only grab the lock if the thread was created successfully -
// then we can also do this check and throw the exception in the
// JavaThread constructor.
if (native_thread->osthread() != NULL) {
// Note: the current thread is not being used within "prepare". //////////////////////////////////////////////////
// 2. 关联java.lang.Thread与JavaThread
//////////////////////////////////////////////////
native_thread->prepare(jthread);
}
}
} if (throw_illegal_thread_state) {
THROW(vmSymbols::java_lang_IllegalThreadStateException());
} assert(native_thread != NULL, "Starting null thread? "); if (native_thread->osthread() == NULL) {
// No one should hold a reference to the 'native_thread'.
delete native_thread;
if (JvmtiExport::should_post_resource_exhausted()) {
JvmtiExport::post_resource_exhausted(
JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR | JVMTI_RESOURCE_EXHAUSTED_THREADS,
"unable to create new native thread");
}
THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(),
"unable to create new native thread");
} //////////////////////////////////////////////////
// 3. 启动JavaThread
//////////////////////////////////////////////////
Thread::start(native_thread); JVM_END

构造JavaThread

来看下JavaThread的构造函数

JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz) :
Thread() //// 各种初始化
#ifndef SERIALGC
, _satb_mark_queue(&_satb_mark_queue_set),
_dirty_card_queue(&_dirty_card_queue_set)
#endif // !SERIALGC
{
if (TraceThreadEvents) {
tty->print_cr("creating thread %p", this);
} ////////////////////////////////////////
// 1. 初始化
////////////////////////////////////////
initialize(); _jni_attach_state = _not_attaching_via_jni;
set_entry_point(entry_point);
// Create the native thread itself.
// %note runtime_23
os::ThreadType thr_type = os::java_thread;
thr_type = entry_point == &compiler_thread_entry ? os::compiler_thread : os::java_thread; ////////////////////////////////////////
// 2. 创建OSThread
////////////////////////////////////////
os::create_thread(this, thr_type, stack_sz); _safepoint_visible = false;
// The _osthread may be NULL here because we ran out of memory (too many threads active).
// We need to throw and OutOfMemoryError - however we cannot do this here because the caller
// may hold a lock and all locks must be unlocked before throwing the exception (throwing
// the exception consists of creating the exception object & initializing it, initialization
// will leave the VM via a JavaCall and then all locks must be unlocked).
//
// The thread is still suspended when we reach here. Thread must be explicit started
// by creator! Furthermore, the thread must also explicitly be added to the Threads list
// by calling Threads:add. The reason why this is not done here, is because the thread
// object must be fully initialized (take a look at JVM_Start)
}

传进来的entry_pointthread_entry。这种方法会调用Thread.run方法。待会就能看到是怎么用的了。

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

创建OSThread

JavaThread的构造函数中会创建OSThread。直接看下Linux下的os::create_thread

bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) {
assert(thread->osthread() == NULL, "caller responsible"); ////////////////////////////////////////
// 1. 构造OSThread
////////////////////////////////////////
// Allocate the OSThread object
OSThread* osthread = new OSThread(NULL, NULL);
if (osthread == NULL) {
return false;
} // set the correct thread state
osthread->set_thread_type(thr_type); ////////////////////////////////////////
// 设置OSThread的状态为ALLOCATED
////////////////////////////////////////
// Initial state is ALLOCATED but not INITIALIZED
osthread->set_state(ALLOCATED); ////////////////////////////////////////
// 关联OSThread与JavaThread
////////////////////////////////////////
thread->set_osthread(osthread); // init thread attributes
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); // stack size
if (os::Linux::supports_variable_stack_size()) {
// calculate stack size if it's not specified by caller
if (stack_size == 0) {
stack_size = os::Linux::default_stack_size(thr_type); switch (thr_type) {
case os::java_thread:
// Java threads use ThreadStackSize which default value can be
// changed with the flag -Xss
assert (JavaThread::stack_size_at_create() > 0, "this should be set");
stack_size = JavaThread::stack_size_at_create();
break;
case os::compiler_thread:
if (CompilerThreadStackSize > 0) {
stack_size = (size_t)(CompilerThreadStackSize * K);
break;
} // else fall through:
// use VMThreadStackSize if CompilerThreadStackSize is not defined
case os::vm_thread:
case os::pgc_thread:
case os::cgc_thread:
case os::watcher_thread:
if (VMThreadStackSize > 0) stack_size = (size_t)(VMThreadStackSize * K);
break;
}
} stack_size = MAX2(stack_size, os::Linux::min_stack_allowed);
pthread_attr_setstacksize(&attr, stack_size);
} else {
// let pthread_create() pick the default value.
} // glibc guard page
pthread_attr_setguardsize(&attr, os::Linux::default_guard_size(thr_type)); ThreadState state; {
// Serialize thread creation if we are running with fixed stack LinuxThreads
bool lock = os::Linux::is_LinuxThreads() && !os::Linux::is_floating_stack();
if (lock) {
os::Linux::createThread_lock()->lock_without_safepoint_check();
} ////////////////////////////////////////
// 2. 使用pthread创建本地子线程
// 本地子线程运行java_start方法。JavaThread作为參数
////////////////////////////////////////
pthread_t tid;
int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread); pthread_attr_destroy(&attr); if (ret != 0) {
if (PrintMiscellaneous && (Verbose || WizardMode)) {
perror("pthread_create()");
}
// Need to clean up stuff we've allocated so far
thread->set_osthread(NULL);
delete osthread;
if (lock) os::Linux::createThread_lock()->unlock();
return false;
} // Store pthread info into the OSThread
osthread->set_pthread_id(tid); ////////////////////////////////////////
// 3. 等待子线程改变OSThread的状态
////////////////////////////////////////
// Wait until child thread is either initialized or aborted
{
Monitor* sync_with_child = osthread->startThread_lock();
MutexLockerEx ml(sync_with_child, Mutex::_no_safepoint_check_flag);
while ((state = osthread->get_state()) == ALLOCATED) {
sync_with_child->wait(Mutex::_no_safepoint_check_flag);
}
} if (lock) {
os::Linux::createThread_lock()->unlock();
}
} // Aborted due to thread limit being reached
if (state == ZOMBIE) {
thread->set_osthread(NULL);
delete osthread;
return false;
} // The thread is returned suspended (in state INITIALIZED),
// and is started higher up in the call chain
assert(state == INITIALIZED, "race condition");
return true;
}

java_start

到这里就能够看到,底层是用的pthread库pthread_create创建的子线程会运行java_start方法,

// Thread start routine for all newly created threads
static 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 above
if (!_thread_safety_check(thread)) {
// notify parent thread
MutexLockerEx 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 thread
os::Linux::hotspot_sigmask(thread); // initialize floating point control register
os::Linux::init_thread_fpu_state(); // handshaking with parent thread
{
MutexLockerEx ml(sync, Mutex::_no_safepoint_check_flag); ////////////////////////////////////////
// 改变OSThread状态
////////////////////////////////////////
// notify parent thread
osthread->set_state(INITIALIZED);
sync->notify_all(); ////////////////////////////////////////
// 等待OSThread状态改变
////////////////////////////////////////
// wait until os::start_thread()
while (osthread->get_state() == INITIALIZED) {
sync->wait(Mutex::_no_safepoint_check_flag);
}
} ////////////////////////////////////////
// 调用JavaThread::run
////////////////////////////////////////
// call one more level start routine
thread->run(); return 0;
}

上面凝视已经说了,子线程会等待OSThread状态的改变才往下运行,那么如今我们须要先回到JVM_StartThread方法,JavaThread::prepare没什么。看下Thread::start

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()) {
// Initialize the thread state to RUNNABLE before starting this thread.
// Can not set it after the thread started because we do not know the
// exact thread state at that time. It could be in MONITOR_WAIT or
// in SLEEPING or some other state.
java_lang_Thread::set_thread_status(((JavaThread*)thread)->threadObj(),
java_lang_Thread::RUNNABLE);
}
////////////////////////////////////////
// 启动JavaThread
////////////////////////////////////////
os::start_thread(thread);
}
}

os::start_thread

void os::start_thread(Thread* thread) {
// guard suspend/resume
MutexLockerEx ml(thread->SR_lock(), Mutex::_no_safepoint_check_flag);
OSThread* osthread = thread->osthread();
////////////////////////////////////////
// 改变OSThread状态
////////////////////////////////////////
osthread->set_state(RUNNABLE);
////////////////////////////////////////
// 调用pd_start_thread
// pd是platform dependent
////////////////////////////////////////
pd_start_thread(thread);
}

此时子线程等待的OSThread状态改变了,能够继续往下运行JavaThread::run了。

JavaThread::run

JavaThread::run

void JavaThread::run() {

  ////////////////////////////////////////
// TLAB,TLS 等初始化
//////////////////////////////////////// // initialize thread-local alloc buffer related fields
this->initialize_tlab(); // used to test validitity of stack trace backs
this->record_base_of_stack_pointer(); // Record real stack base and size.
this->record_stack_base_and_size(); // Initialize thread local storage; set before calling MutexLocker
this->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_vm
ThreadStateTransition::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);
} EventThreadStart event;
if (event.should_commit()) {
event.set_javalangthread(java_lang_Thread::thread_id(this->threadObj()));
event.commit();
} // 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 computed
thread_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); ////////////////////////////////////////
// 运行一開始传入的thread_entry
// 也就是java.lang.Thread#run
////////////////////////////////////////
this->entry_point()(this, this);
} DTRACE_THREAD_PROBE(stop, this); ////////////////////////////////////////
// 运行清理工作
////////////////////////////////////////
this->exit(false);
////////////////////////////////////////
// 销毁JavaThread
////////////////////////////////////////
delete this;
}

妥妥的,也就是说是由pthread_create出来的线程来运行了Thread.run方法。1:1的线程模型。

參考资料

HotSpotVM 线程实现浅析的更多相关文章

  1. ThreadPoolExecutor 线程池浅析

    作为Executor框架中最核心的类,ThreadPoolExecutor代表着鼎鼎大名的线程池,它给了我们足够的理由来弄清楚它. 下面我们就通过源码来一步一步弄清楚它. 内部状态 线程有五种状态:新 ...

  2. Qt中的多线程与线程池浅析+实例

    1. Qt中的多线程与线程池 今天学习了Qt中的多线程和线程池,特写这篇博客来记录一下 2. 多线程 2.1 线程类 QThread Qt 中提供了一个线程类,通过这个类就可以创建子线程了,Qt 中一 ...

  3. 阻塞和唤醒线程——LockSupport功能简介及原理浅析

    目录 1.LockSupport功能简介 1.1 使用wait,notify阻塞唤醒线程 1.2 使用LockSupport阻塞唤醒线程 2. LockSupport的其他特色 2.1 可以先唤醒线程 ...

  4. IO模型、线程模型

    五种IO模型介绍和对比 https://juejin.im/post/5bd32b84f265da0ac962e7c9 Linux 的 IO 通信 以及 Reactor 线程模型浅析 https:// ...

  5. JDK源码那些事儿之浅析Thread上篇

    JAVA中多线程的操作对于初学者而言是比较难理解的,其实联想到底层操作系统时我们可能会稍微明白些,对于程序而言最终都是硬件上运行二进制指令,然而,这些又太过底层,今天来看一下JAVA中的线程,浅析JD ...

  6. 软件工程(C编码实践篇)总结

    陆伟丹 + 原创作品转载请注明出处 + <软件工程(C编码实践篇)>MOOC课程http://mooc.study.163.com/course/USTC-1000002006 对软件工程 ...

  7. 软件工程(C编码实践篇)课程总结

    课程内容来自网易云课堂中科大孟宁老师的软件工程(C编码实践篇)课程. 课程页面 我觉得本门课程的设置非常科学,每一周课程都是基于上一周课程的进一步抽象,使得学习者能够循序渐进,逐渐加深对软件工程的理解 ...

  8. ThreadPool study

    线程池浅析 线程池顾名思义就是放线程的池子 Thread Pool. 那么为什么要有线程池呢?有些时候系统需要处理非常多的执行时间很短的请求,如果每一个请求都开启一个新的线程,则系统创建销毁线程的开销 ...

  9. CPU的CAS操作

    https://blog.csdn.net/qq_35492857/article/details/78471032 https://www.cnblogs.com/gdjdsjh/p/5076815 ...

随机推荐

  1. Sublime Text2安装emmet

    一.安装Package Control 如果Preferences中没有Package Control,需要手动安装.安装方法如下: 访问Package Controls站点复制一段python命令安 ...

  2. 如何成为一名出色的Oracle数据库管理员

    主要针对Oracle DBA在成长阶段的定位,学习方法等几大方面进行了经典的论述,详细内容请参考下文. 一.定位 Oracle分两大块,一块是开发,一块是管理.开发主要是写写存储过程.触发器什么的,还 ...

  3. [Windows Server 2012] 安装护卫神·主机管理系统

    ★ 欢迎来到[护卫神·V课堂],网站地址:http://v.huweishen.com★ 护卫神·V课堂 是护卫神旗下专业提供服务器教学视频的网站,每周更新视频.★ 本节我们将带领大家:安装护卫神·主 ...

  4. 12、scala函数式编程集合

    1.Scala的集合体系结构 2.List 3.LikedList 4.Set 5.集合的函数式编程 6.函数式编程综合案例:统计单词总数 1.Scala的集合体系结构 Scala中集合体系主要包括: ...

  5. Tomcat服务器安装与第一个jsp网页程序

    1.安装tomcat服务器之前需要,先安装相应版本的jdk,个人理解Tomcat的大部分功能是使用了java的 jdk jar包的. jdk包下载方式网上可以查到 下载完后可以解压到一个指定目录,并在 ...

  6. python numpy array 与matrix 乘方

    python numpy array 与matrix 乘方 编程语言 waitig 1年前 (2017-04-18) 1272℃ 百度已收录 0评论 数组array 的乘方(**为乘方运算符)是每个元 ...

  7. c++ map: 使用struct或者数组做value

    Notice 如果是program中有两个map对象,可能你需要两个map iterator,但是注意两个iter object不能命名一样,可以分别为iter1, iter2 Example #in ...

  8. Linq表达式写法

    Linq表达式,实现按照某个字段排序的简单写法. 做项目的时候遇到的一个简单问题,于是记下来. 列举一个例子: <T> model=new <T>(); 加入model中有要根 ...

  9. BZOJ 4032 Luogu P4112 [HEOI2015]最短不公共子串 (DP、后缀自动机)

    这其实是道水题... 题目链接: (bzoj)https://www.lydsy.com/JudgeOnline/problem.php?id=4032 (luogu)https://www.luog ...

  10. 解析特殊格式的xml到map

    由于项目特殊,需要解析的xml文档样式特别,所以自己写了一个解析特殊xml的方法 先提供xml样式 <?xml version="1.0" encoding="UT ...