Monitor Ctrl-Break 线程不见了!?
于是,我问他:
是啊,问题解决了,但是啥原因啊?
为什么 Run 不可以运行,而 Debug 可以运行呢?
当前线程有哪些?
我们先梳理一下当前线程有哪些吧。
可以使用下面的代码获取当前所有的线程:
public static Thread[] findAllThread(){ ThreadGroup currentGroup =Thread.currentThread().getThreadGroup(); while (currentGroup.getParent()!=null){ // 返回此线程组的父线程组 currentGroup=currentGroup.getParent(); } //此线程组中活动线程的估计数 int noThreads = currentGroup.activeCount(); Thread[] lstThreads = new Thread[noThreads]; //把对此线程组中的所有活动子组的引用复制到指定数组中。 currentGroup.enumerate(lstThreads); for (Thread thread : lstThreads) { System.out.println("线程数量:"+noThreads+" " + "线程id:" + thread.getId() + " 线程名称:" + thread.getName() + " 线程状态:" + thread.getState()); } return lstThreads; }
运行之后可以看到有 6 个线程:
也就是说,在 idea 里面,一个 main 方法 Run 起来之后,即使什么都不干,也会有 6 个线程运行。
这 6 个线程分别是干啥的呢?
我们一个个的说。
Reference Handler 线程:
JVM 在创建 main 线程后就创建 Reference Handler 线程,其优先级最高,为 10,它主要用于处理引用对象本身(软引用、弱引用、虚引用)的垃圾回收问题。
Finalizer 线程:
这个线程也是在 main 线程之后创建的,其优先级为10,主要用于在垃圾收集前,调用对象的 finalize() 方法。
关于 Finalizer 线程的几点:
1)只有当开始一轮垃圾收集时,才会开始调用 finalize() 方法;因此并不是所有对象的 finalize() 方法都会被执行;
2)该线程也是 daemon 线程,因此如果虚拟机中没有其他非 daemon 线程,不管该线程有没有执行完 finalize() 方法,JVM 也会退出;
3) JVM在垃圾收集时会将失去引用的对象包装成 Finalizer 对象(Reference的实现),并放入 ReferenceQueue,由 Finalizer 线程来处理;最后将该 Finalizer 对象的引用置为 null,由垃圾收集器来回收;
4) JVM 为什么要单独用一个线程来执行 finalize() 方法呢?如果 JVM 的垃圾收集线程自己来做,很有可能由于在 finalize() 方法中误操作导致 GC 线程停止或不可控,这对 GC 线程来说是一种灾难。
Attach Listener 线程:
Attach Listener 线程是负责接收到外部的命令,而对该命令进行执行的并且把结果返回给发送者。通常我们会用一些命令去要求 jvm 给我们一些反馈信息。
如:java -version、jmap、jstack 等等。如果该线程在 jvm 启动的时候没有初始化,那么,则会在用户第一次执行 jvm 命令时,得到启动。
Signal Dispatcher 线程:
前面我们提到第一个 Attach Listener 线程的职责是接收外部 jvm 命令,当命令接收成功后,会交给 signal dispather 线程去进行分发到各个不同的模块处理命令,并且返回处理结果。signal dispather 线程也是在第一次接收外部 jvm 命令时,进行初始化工作。
main 线程:
呃,这个不说了吧。大家都知道。
Monitor Ctrl-Break 线程:
先买个关子,下一小节专门聊聊这个线程。
上面线程的作用,我是从这个网页搬运过来的,还有很多其他的线程,大家可以去看看:
我好事做到底,直接给你来个长截图,一网打尽。
你先把图片保存起来,后面慢慢看:
现在跟着我去探寻 Monitor Ctrl-Break 线程的秘密。