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异步的发到想要停止的线程。
- // Enqueue a VM_Operation to do the job for us - sometime later
- void Thread::send_async_exception(oop java_thread, oop java_throwable) {
- VM_ThreadStop* vm_stop = new VM_ThreadStop(java_thread, java_throwable);
- VMThread::execute(vm_stop);
- }
VM_ThreadStop 是一个vm_operations.cpp里定义的一个operation.
在jvm里面有一个内部线程叫VM_Thread, 专门负责和处理这些opertaion
"VM Thread" prio=10 tid=0x00007f9de3549800 nid=0x722 runnable
在方法里轮询_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种模式
- enum Mode {
- _safepoint, // blocking, safepoint, vm_op C-heap allocated
- _no_safepoint, // blocking, no safepoint, vm_op C-Heap allocated
- _concurrent, // non-blocking, no safepoint, vm_op C-Heap allocated
- _async_safepoint // non-blocking, safepoint, vm_op C-Heap allocated
- };
而VM_ThreadStop 定义为_async_safepoint,是属于SafepointPriority的优先级别
VM_Operation->evaluate方法,最后是调用VM_ThreadStop doit()
- void VM_ThreadStop::doit() {
- assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint");
- JavaThread* target = java_lang_Thread::thread(target_thread());
- // Note that this now allows multiple ThreadDeath exceptions to be
- // thrown at a thread.
- if (target != NULL) {
- // the thread has run and is not already in the process of exiting
- target->send_thread_stop(throwable());
- }
- }
最后是把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线程。