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