[KANMARS原创] - (五) 从JVM源码来理解JVM中的线程种类与启动方式
JVM中的线程详解
在JVM的\hotsopt\src\share\vm\runtime\Thread.hpp中可以看到关于THREAD的子类结构
// Class hierarchy
// - Thread
// - NamedThread
// - VMThread
// - ConcurrentGCThread
// - WorkerThread
// - GangWorker
// - GCTaskThread
// - JavaThread
// - LowMemoryDetectorThread
// - CompilerThread
// - WatcherThread
Thread是最基础的基类
重要属性如下:
OSThread _osthread;
在OSThread内部set_thread_id方法可以设置为操作系统级的线程ID pthreadid
在JVM的线程管理中,THREAD是一个数据结构,THREAD中含有抽象的OSThread数据结构,OSThread中的pthreadid或者threadid指向的是操作系统内核级别的线程id
关于操作系统内核级别的线程,大家可以阅读原生C语言的多线程编程接口POSIX threads 简称pthread库
重要函数如下:
virtual void run(); 为最终的线程运行方法
此外有一个工具性质的类Threads
重要属性如下:
static JavaThread _thread_list;
static int _number_of_threads;
static int _number_of_non_daemon_threads;
static int _return_code;
储存了所有正在运行的Java线程
————————————————————————————————————————————————————————————————
可以看到,线程粗分为三类:
NamedThread、JavaThread、WatcherThread
这三类中
NamedThread是一个大类
按照源码中的注释:
// Name support for threads. non-JavaThread subclasses with multiple
// uniquely named instances should derive from this.
max_name_len = 64,最大名称长度为64个字符
重要属性为
char _name;
JavaThread _processed_thread;
也就是说NamedThread中可以有OSThread也可以有JavaThread
JavaThread是JAVA线程
重要属性如下:
JavaThread _next; // The next thread in the Threads list
oop _threadObj; // The Java level thread object
int _java_call_counter; // java调用次数
JavaFrameAnchor _anchor; // JavaFrame锚点
ThreadFunction _entry_point;
JNIEnv _jni_environment;
vframeArray _vframe_array_head;
vframeArray _vframe_array_last;
GrowableArray<jvmtiDeferredLocalVariableSet> _deferred_locals_updates; 本地变量表
oop _vm_result; // Used to pass back an oop result into Java code, GC-preserved
oop _vm_result_2; // Used to pass back an oop result into Java code, GC-preserved
ThreadSafepointState _safepoint_state;
address _saved_exception_pc;
volatile oop _exception_oop;
volatile address _exception_pc;
volatile address _exception_handler_pc;
volatile int _exception_stack_size;
volatile int _is_method_handle_return;
重要方法如下:
void java_suspend();
void java_resume();
int java_suspend_self();
virtual void run();
WatcherThread是用来模拟时间中断
重要属性如下:
static WatcherThread _watcher_thread;
volatile static bool _should_terminate;
————————————————————————————————————————————————————————————————
// - NamedThread
// - VMThread
// - ConcurrentGCThread
// - WorkerThread
// - GangWorker
// - GCTaskThread
NameThread下分为三大类VMThread,ConcurrentGCThread,WorkerThread
首先看VMThread
VMThread位于\hotspot\src\share\vm\runtime\vmThread.hpp中
重要属性如下:
static VM_Operation _cur_vm_operation; 当前正在执行的VM操作
static VMOperationQueue _vm_queue; 所有VM操作的对象
static VMThread _vm_thread; 单例模式的VMThread
重要方法如下:
void evaluate_operation(VM_Operation op); 执行一个VM操作
bool is_VM_thread() const { return true; } //默认为VMThread
bool is_GC_thread() const { return true; } //默认为GCThread
与VMThread配套使用的是VMOperationQueue和VM_Operation
VMOperationQueue位于\hotspot\src\share\vm\runtime\vmThread.hpp中
重要属性如下:
int _queue_length[nof_priorities];
VM_Operation _queue [nof_priorities];
int _queue_counter;
VM_Operation _drain_list;
VM_Operation位于\hotspot\src\share\vm\runtime\Vm_operations.hpp中
重要属性如下:
Thread _calling_thread;
VM_Operation _next;
VM_Operation _prev;
void evaluate();
virtual void doit()
virtual bool doit_prologue()
virtual void doit_epilogue()
VM_ThreadStop位于\hotspot\src\share\vm\runtime\Vm_operations.hpp中
重要属性如下
oop _thread;
oop _throwable;
此外和VMThread相关联的VM_Operation还有
VM_ForceSafepoint
VM_ForceAsyncSafepoint
VM_Deoptimize
VM_DeoptimizeFrame
VM_HandleFullCodeCache
VM_DeoptimizeAll
VM_ZombieAll
VM_Verify
VM_PrintThreads
VM_PrintJNI
VM_FindDeadlocks
VM_ThreadDump
VM_Exit
可从名称中看到其用途
举个简单的栗子,VM_PrintJNI
void VM_Operation::evaluate() {
ResourceMark rm;
if (TraceVMOperation) {
tty->print(“[“);
NOT_PRODUCT(print();)
}
doit();
if (TraceVMOperation) {
tty->print_cr(“]”);
}
}
void VM_PrintJNI::doit() {
JNIHandles::print_on(_out);
}
—————————————————————-
ConcurrentGCThread位于\hotspot\src\share\vm\gc_implementation\shared\concurrentGCThread.hpp中
含义如其名称,并发垃圾回收线程
WorkerThread有两个子类:GangWorker、GCTaskThread
子类极多。启动过程有很大区别,例如
GangWorker在WorkGang::initialize_workers()中GangWorker new_worker = allocate_worker(worker);中创建
例如FlexibleWorkGang _workers->initialize_workers();
GCTaskThread的初始化与启动在
ParallelScavengeHeap::initialize()
_gc_task_manager = GCTaskManager::create(ParallelGCThreads);
在构造函数中调用:initialize();
GCTaskManager::initialize()
set_thread(t, GCTaskThread::create(this, t, processor_assignment[t]));
new GCTaskThread(manager, which, processor_id)
os::create_thread(this, os::pgc_thread)
osthread->set_thread_type(thr_type);
thread->run();
GCTaskThread->run();
GCTask task = manager()->get_task(which()); 即:任何一个进程,只要在manager的任务队列中放入task,后续将会立刻执行
task->do_it(manager(), which());
从这段描述中可以看到,WorkerThread本身即为垃圾回收线程,大致分为两类:
1、GangWorker,作用于SharedHeap,在ShareHeap创建成功后,等待AbstractWorkGang->AbstractGangTask _task中获取到task,然后执行
2、GCTaskThread,作用于parallelscavenge,在ParallelScavengeHeap创建成功后,生成GCTaskManager,进而生成任务队列SynchronizedGCTaskQueue _queue,等待有程序将任务放入队列,然后执行
—————————————————————-
下文我们来看一下VMThread的启动过程
VMThread是用于JVM虚拟机操作
其启动过程为随着JVM虚拟机java.c一起启动
调用堆栈序列为:
java.c:main->javaMain->InitializeJVM->CreateJavaVM->JNI_CreateJavaVM->Threads::create_vm
VMThread::create(); 生成单例模式的_vm_thread
_vm_thread = new VMThread();
_vm_queue = new VMOperationQueue();
os::create_thread(vmthread, os::vm_thread) 给VMThread创建真实线程
OSThread osthread = new OSThread(NULL, NULL);
pd_initialize();
_startThread_lock = new Monitor(Mutex::event, “startThread_lock”, true); 锁监视器,第一个和第三个参数均没有用,只有第二个参数会作为Monitor的名名称
内部具有_LockWord关键字,同时具有CASPTR宏Atomic::cmpxchg_ptr用来对数据进行原子性操作,底层采用AMD64汇编指令cmpxchgq来完成原子性操作
Monitor::Monitor() { ClearMonitor(this); }
void Monitor::ClearMonitor (Monitor m, const char name) {
m->_owner = NULL ;
m->_snuck = false ;
if (name == NULL) {
strcpy(m->_name, “UNKNOWN”) ;
} else {
strncpy(m->_name, name, MONITOR_NAME_LEN - 1);
m->_name[MONITOR_NAME_LEN - 1] = ‘\0’;
}
m->_LockWord.FullWord = 0 ;
m->_EntryList = NULL ;
m->_OnDeck = NULL ;
m->_WaitSet = NULL ;
m->_WaitLock[0] = 0 ;
}
可看到锁的初始值是m->_LockWord.FullWord = 0 ;
此处需要注意:Monitor中的lockWord为SplitWord
union SplitWord { // full-word with separately addressable LSB
volatile intptr_t FullWord ;
volatile void Address ;
volatile jbyte Bytes [sizeof(intptr_t)] ;
}
因此,lockWord初始值为0
而ILock中代码如下intptr_t v = CASPTR (&_LockWord, 0, _LBIT) ;
锁定后_LockWord = 1,解锁后_LockWord = 0;
初始值为未锁定0
vmthread->set_osthread(osthread);
pthread_t tid;
int ret = pthread_create(&tid, &attr, (void ()(void)) java_start, thread);
osthread->set_pthread_id(tid);
在java_start函数中
while (osthread->get_state() == INITIALIZED) {
sync->wait(Mutex::_no_safepoint_check_flag); 开始等待
等待函数的写法如下:
Thread const Self = Thread::current() ;
set_owner(NULL);
wait_status = IWait (Self, timeout) ; 开始等待–>内部实现细节需要研究
set_owner (Self) ;
}
thread->run(); 开始调用thread->run函数
os::start_thread(vmthread);
调用: pd_start_thread(thread);
调用: Monitor* sync_with_child = osthread->startThread_lock();
调用: MutexLockerEx ml(sync_with_child, Mutex::_no_safepoint_check_flag);
调用: sync_with_child->notify(); 通知java_start继续运行
调用: thread->run()
调用: this->loop();
代码: while(true)
代码: _cur_vm_operation = _vm_queue->remove_next();
代码: evaluate_operation(_cur_vm_operation);
代码: _cur_vm_operation->evaluate();
代码: _cur_vm_operation->doit();
在最终的doit()函数中,即执行的是VM_Operation的操作。
例如:
void VM_PrintThreads::doit() {
Threads::print_on(_out, true, false, _print_concurrent_locks);
}
这个就是VMThread的执行步骤,以及最终调用函数的过程。