首页 > 技术文章 > 启动一个最简单的Java main程序时,有多少个线程被创建

Jason2018 2018-07-15 10:26 原文

 在java中,启动一个简单的main程序,并不是只是单单创建了一个main线程而已,JVM会自动创建一些辅助用的线程,主要有以下几个:

  Attach Listener:Attach Listener线程是负责接收到外部的命令,而对该命令进行执行的并且吧结果返回给发送者。通常我们会用一些命令去要求jvm给我们一些反 馈信 息,如:java -version、jmap、jstack等等。如果该线程在jvm启动的时候没有初始化,那么,则会在用户第一次执行jvm命令时,得到启动。

  Signal Dispatcher:前面我们提到第一个Attach Listener线程的职责是接收外部jvm命令,当命令接收成功后,会交给signal dispather线程去进行分发到各个不同的模块处理命令,并且返回处理结果。signal dispather线程也是在第一次接收外部jvm命令时,进行初始化工作。

  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线程来说是一种灾难;

  Reference Handler:VM在创建main线程后就创建Reference Handler线程,其优先级最高,为10,它主要用于处理引用对象本身(软引用、弱引用、虚引用)的垃圾回收问题。

以上这部分内容引用自 http://ifeve.com/jvm-thread/,可以取这个地址查看更多线程的信息

这4个线程,加上,main,所以总共会有5个线程被创建,可以通过这几行代码来查看

ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();

ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false,false);

for (ThreadInfo info : threadInfos ) {

  System.out.println("[" + info.getThreadId() + "]" + info.getThreadName());

}

  但是,当前活动的线程只有1个,就是main,System.out.println(Thread.activeCount()); 用这条命令返回值是1。这也经常被用作以下场合的判断

比如,在main线程中创建多个子线程后,如果子线程的耗时比main线程要长,main线程就会再子线程之前结束。假如main线程的结果需要用到子线程的返回值,那么我们通常就在main线程中加上这句代码:

  System.out.println(Thread.activeCount() >1),

来判断子线程是否全部运行结束,也就是当前活动线程只有main线程一个。这样做在windows下是没错的,但是!!!

在linux下就不是这样了,你会发现,即使所有的子线程全部结束,打印当前的活动线程是2!!!而不是1,除了main线程之外,linux下还会有一个Monitor Ctrl-Break 线程存在,这个线程是用来干嘛的呢?

Monitoring Thread Activity With Thread Dumps Thread dumps, or "thread stack traces," reveal information about an application's activity that can help you diagnose problems and better optimize application and JVM performance; for example, thread dumps can show the occurrence of "deadlock" conditions, which can seriously impact application performance. You can create a thread dump by invoking a control break (usually by pressing Ctrl-Break or Ctrl-\ or SIGQUIT on linux). This section provides information on working with thread dumps. It includes information on these subjects: 1.Lock Information in Thread Dumps 2.Detecting Deadlocks

这是oracle官网的原话。大家可以自行翻译。 结论:在windows下可以用 Thread.activeCount() >1来判断子线程是否全部结束,但是linux中应该是 Thread.activeCount() > 2

推荐阅读