JVM Thread stop 的源码分析

在JVM, Thread.stop 是被阻止的方法,看原语义

该方法具有固有的不安全性。用 Thread.stop 来终止线程将释放它已经锁定的所有监视器(作为沿堆栈向上传播的未检查 <font face="Courier New">ThreadDeath</font> 异常的一个自然后果)。如果以前受这些监视器保护的任何对象都处于一种不一致的状态,则损坏的对象将对其他线程可见,这有可能导致任意的行为。<font face="Courier New">stop</font> 的许多使用都应由只修改某些变量以指示目标线程应该停止运行的代码来取代。目标线程应定期检查该变量,并且如果该变量指示它要停止运行,则从其运行方法依次返回。如果目标线程等待很长时间(例如基于一个条件变量),则应使用 <font face="Courier New">interrupt</font>方法来中断该等待。有关更多信息,

而interrupt的语义适合等待中的打断,如何停止线程是个有意思的话题,先来看看jvm 阻止的thread.stop如何实现

Thread.stop 主要是调用 jvm.cpp,JVM_StopThread 方法,

Thread::send_async_exception(Java_thread, JNIHandles::resolve(throwable));

对调用thread.stop 非本线程的时候,需要把ThreadDeath异步的发到想要停止的线程。

  1. // Enqueue a VM_Operation to do the job for us - sometime later   
  2. void Thread::send_async_exception(oop java_thread, oop java_throwable) {  
  3.   VM_ThreadStop* vm_stop = new VM_ThreadStop(java_thread, java_throwable);  
  4.   VMThread::execute(vm_stop);  
  5. }  

VM_ThreadStop 是一个vm_operations.cpp里定义的一个operation.

在jvm里面有一个内部线程叫VM_Thread, 专门负责和处理这些opertaion

"VM Thread" prio=10 tid=0x00007f9de3549800 nid=0x722 runnable 

也就是停止线程的事件,并不是当前线程处理的,而是交给VM thread 这个线程处理
在 VMThread 的结构体里有一个_vm_queue 的VMOperationQueue结构体, 而vm_operation的操作会被放入到VMOperationQueue里的_queue优先级的队列中.
在JVM里面定义了3种优先级队列
SafepointPriority == 0  MediumPriority == 1 nof_priorities =2
而如何定义哪个优先级别,这里的算法很有意思,就是算queue的长度,如果<10了那么将认为SafepointPriority 为high priority
否则就认为MediumPriority 是high priority
VmThread 本身是一个自轮询的线程,具体实现方法见vmThread.cpp.
void VMThread::loop()

在方法里轮询_vm_queue,把queue优先级队列(如何判断优先级见上面的注释)里的第一个vm_operation设置到_cur_vm_operation,并把数组中的所有SafepointPriority级别的vm_opration drain到另一个链表结构的_drain_list,执行_cur_vm_operation和_drain_list 里的VM_Operation的evaluate方法。

VM_Operation有4种模式

  1. enum Mode {  
  2.     _safepoint,       // blocking,        safepoint, vm_op C-heap allocated   
  3.     _no_safepoint,    // blocking,     no safepoint, vm_op C-Heap allocated   
  4.     _concurrent,      // non-blocking, no safepoint, vm_op C-Heap allocated   
  5.     _async_safepoint  // non-blocking,    safepoint, vm_op C-Heap allocated   
  6.   };  

而VM_ThreadStop 定义为_async_safepoint,是属于SafepointPriority的优先级别

VM_Operation->evaluate方法,最后是调用VM_ThreadStop doit()

  1. void VM_ThreadStop::doit() {  
  2.   assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint");  
  3.   JavaThread* target = java_lang_Thread::thread(target_thread());  
  4.   // Note that this now allows multiple ThreadDeath exceptions to be   
  5.   // thrown at a thread.   
  6.   if (target != NULL) {  
  7.     // the thread has run and is not already in the process of exiting   
  8.     target->send_thread_stop(throwable());  
  9.   }  
  10. }  

最后是把throwable的error,也就是设置Thread里的_pending_async_exception为threaddeath,设置线程的_special_runtime_exit_condition 的状态设置为_async_exception,同时设置线程的_suspend_flags值为_has_async_exception。

注意在这里只是设置了异步的exception,和设置了运行退出的状态为_async_exception, 并没有直接设置_pending_exception,也就是说要终止的线程运行过程中发现有has_async_exception 执行check_and_handle_async_exceptions,才把_pending_async_exception赋值到_pending_exception,被线程执行并抛出这个异常。 

因为thread 当前状态有可能在wait/sleep, 所以同时interrupt线程。

相关推荐