【问题标题】:Why does a single threaded java program have so many threads?为什么一个单线程的java程序会有这么多线程?
【发布时间】:2015-06-25 01:35:39
【问题描述】:

我有一个 Java 程序,它有 13 个线程,尽管其中只有一个线程的 CPU 使用率为 99%,并且已经运行了大约 24 小时。其他的 CPU 使用率为 0.0%,并显示从 0:00.0 到 0:12.82 的任意位置的 TIME+,其中一个具有 3:51.48。该程序旨在成为单线程程序,所以我想知道为什么其他线程在那里?

他们在做什么?为什么他们的 cpu 使用率和 TIME+ 这么少?

更新:我编写了一个旧的 java 程序(第一个程序 - 不要评判我!)它是单线程的,并且显示了相同类型的线程使用...

import java.io.*;

class xdriver {
  static int N = 100;
  static double pi = 3.141592653589793;
  static double one = 1.0;
  static double two = 2.0;

  public static void main(String[] args) {
    //System.out.println("Program has started successfully\n");

    if( args.length == 1) {
      // assume that args[0] is an integer
      N = Integer.parseInt(args[0]);
    }   

    // maybe we can get user input later on this ...
    int nr = N;
    int nt = N;
    int np = 2*N;

    double dr = 1.0/(double)(nr-1);
    double dt = pi/(double)(nt-1);
    double dp = (two*pi)/(double)(np-1);

    System.out.format("nn --> %d\n", nr*nt*np);

    if(nr*nt*np < 0) {
      System.out.format("ERROR: nr*nt*np = %d(long) which is %d(int)\n", (long)( (long)nr*(long)nt*(long)np), nr*nt*np);
      System.exit(1);
    }   

    // inserted to artificially blow up RAM
    double[][] dels = new double [nr*nt*np][3];

    double[] rs = new double[nr];
    double[] ts = new double[nt];
    double[] ps = new double[np];

    for(int ir = 0; ir < nr; ir++) {
      rs[ir] = dr*(double)(ir);
    }   
    for(int it = 0; it < nt; it++) {
      ts[it] = dt*(double)(it);
    }   
    for(int ip = 0; ip < np; ip++) {
      ps[ip] = dp*(double)(ip);
    }   

    double C = (4.0/3.0)*pi;
    C = one/C;

    double fint = 0.0;
    int ii = 0;
    for(int ir = 0; ir < nr; ir++) {
      double r = rs[ir];
      double r2dr = r*r*dr;
      for(int it = 0; it < nt; it++) {
        double t = ts[it];
        double sint = Math.sin(t);
        for(int ip = 0; ip < np; ip++) {
          fint += C*r2dr*sint*dt*dp;

          dels[ii][0] = dr; 
          dels[ii][1] = dt; 
          dels[ii][2] = dp; 
        }   
      }   
    }   

    System.out.format("N ........ %d\n", N); 
    System.out.format("fint ..... %15.10f\n", fint);
    System.out.format("err ...... %15.10f\n", Math.abs(1.0-fint));
  }
}

【问题讨论】:

  • 其中一些可能与垃圾收集有关。它是一个什么样的程序?有图形界面吗?
  • 请发布您的程序!
  • 无 GUI - 我指定 -XX:ParallelGCThreads=1 -XX:+UseConcMarkSweepGC 所以它是单线程 GC。
  • 能否提供线程堆栈信息。
  • @GaneshThiagarajan 这不是我的程序。我正在与运行 3rd 方代码的人一起工作,并且想知道它为什么会这样。

标签: java multithreading


【解决方案1】:

启动 Java 程序意味着启动 JVM 并告诉它要运行哪个主类(通常具有静态 main 方法)。

除了上面提到的主线程之外,这个 JVM 还产生了几个后台线程。

其中有

  • VM 线程:等待需要 VM 处于安全点的任务的观察线程。例如,有一个垃圾回收任务,它完全“停止了世界”。但还有其他人。
  • GC 线程:为运行垃圾回收而维护的多个线程。
  • 编译线程:这些线程用于将字节码编译为本机机器码。

可能还有更多。

此外,如果您使用 AWT 或 Swing,您将从这些框架中获得更多线程。其中之一是所谓的事件调度程序 thred (EDT)。而且 - 当然 - 可能有您创建并运行的线程:计时器、执行程序或只是一些任意线程。即使对于一个简单的 hello world 应用程序,也可能有十几个线程在运行。

但是这些线程中的大多数都在等待而不是在做某事。所以很有可能只有一个线程真正在工作,从而占用了一些 CPU。

虽然 ... 100% CPU 利用率可能表明存在某些问题。例如,一个永无止境的循环。您必须使用分析器来找出真正发生的事情。但它可能只是一个具有这种 CPU 利用率的程序。您的判断。

【讨论】:

  • @Laurbert515 你可能想使用 jvisualvm 来显示线程的名称。它使您能够显示一个线程转储,告诉您哪些代码/类正在线程中运行
  • 无关:今天我(希望)得到传说中的黄金......只是感谢所有让我学到很多东西的人......
【解决方案2】:

引用完成的讨论here 和其他研究。

少数核心JVM线程:

  1. 附加监听器: 这是一个始终监听其他 JVM 线程发送请求的线程。一个实际的例子是分析或(我不是关于这个)生产级应用程序监控工具,如 DynaTrace。
  2. 信号调度器:当操作系统向 JVM 发出信号时,信号调度器线程会将信号传递给相应的处理程序。
  3. Reference Handler:高优先级线程将待处理的引用排入队列。 GC 创建一个需要处理的引用的简单链表,该线程快速将它们添加到适当的队列中并通知 ReferenceQueue 侦听器。
  4. 终结器:终结器线程调用终结器方法。
  5. DestroyJavaVM: 该线程在程序退出时卸载 Java VM。大多数时候它应该在等待。
  6. 垃圾收集器:负责 Java 垃圾收集机制的线程,取决于是否启用了 GC。
  7. ma​​in: 运行您的程序的主线程,包含main 方法。

一个需要注意的重要一点是它将取决于 JVM 实现,它将启动多少核心线程以及所有核心线程,但即使 Java 程序被编写为单线程,也会有JVM 中有多个线程。

Java 程序可以是单线程的,但 JVM(它将运行用户定义的 Java 程序)是多线程的,并且(至少对于最新的 JVM)甚至从一开始就拥有多个线程。

下面是我的 Java HotSpot(TM) 客户端 VM 版本 24.55-b03 的快照,运行单线程 Java 程序:

回答您的问题

他们在做什么,为什么他们的 cpu 使用率如此之低, 时间+?

哪一部分: JVM 启动是为了一个目的,就像上面解释的,JVM 想要监听是否有任何分析或监控程序想要从 JVM 获取一些细节。
为什么部分:因为它们实际上没有处于活动或运行状态,它们处于等待或停放状态(请参阅我附加快照中的黄色线程,如果您有 GUI 监控应用程序,那么您还应该看到 Yellow 或 else if 命令线然后线程处于等待状态),因此它们不占用任何或最少的 CPU 周期,因此 CPU 使用率更低。 再次TIME+ 会显示他们已经活动的时间,因为他们没有,所以这个参数也更少。

希望这会有所帮助!

【讨论】:

    【解决方案3】:

    很可能线程已在某处创建并且从未使用过。

    例如:

    ExecutorService es = Executors.newFixedThreadPool(12);
    // burn cpu, using only one thread (main)
    int i = 0;
    while(true) {
        i++;
    }
    

    【讨论】:

      【解决方案4】:

      TIME+ 从顶部开始是 CPU 花费的时间量。一种解释是,如果一个进程不断阻塞或总是阻塞,那么它将同时具有低 CPU 使用率和低 TIME+。

      【讨论】:

        猜你喜欢
        • 2013-03-23
        • 1970-01-01
        • 1970-01-01
        • 2013-11-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-07-21
        • 2017-09-24
        相关资源
        最近更新 更多