Подтвердить что ты не робот

Пример простой Java работает с 14 потоками. Зачем?

Следующий тривиальный код Java:

public class Main {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("Start");
        Thread.sleep(5000);
        System.out.println("Done");
    }
}

Работает с использованием 14 потоков. Я знаю, что theres какой-то поток GC работает в фоновом режиме, но для чего нужны другие? Почему так много потоков? Я на Gentoo Linux с Java 1.6.0_26. Компиляция с компилятором Eclipse или javac не имеет значения (запуск в Eclipse в режиме отладки добавляет к нему еще 3 потока, но это, вероятно, оправдано).

4b9b3361

Ответ 1

My JVM (1.6.0_26) порождает еще больше потоков по умолчанию. Большинство из них имеют довольно описательные имена, которые намекают на их назначение:

"Attach Listener" daemon prio=10 tid=0x0000000041426800 nid=0x2fb9 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Low Memory Detector" daemon prio=10 tid=0x00007f512c07e800 nid=0x2fa3 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread1" daemon prio=10 tid=0x00007f512c07b800 nid=0x2fa2 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" daemon prio=10 tid=0x00007f512c078800 nid=0x2fa1 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" daemon prio=10 tid=0x00007f512c076800 nid=0x2fa0 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" daemon prio=10 tid=0x00007f512c05a000 nid=0x2f9f in Object.wait() [0x00007f512b8f7000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00000007c14b1300> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)
    - locked <0x00000007c14b1300> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134)
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)

"Reference Handler" daemon prio=10 tid=0x00007f512c058000 nid=0x2f9e in Object.wait() [0x00007f512b9f8000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00000007c14b11d8> (a java.lang.ref.Reference$Lock)
    at java.lang.Object.wait(Object.java:485)
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
    - locked <0x00000007c14b11d8> (a java.lang.ref.Reference$Lock)

"main" prio=10 tid=0x0000000041401800 nid=0x2f94 waiting on condition [0x00007f5135735000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
    at java.lang.Thread.sleep(Native Method)
    at Main.main(Main.java:5)

"VM Thread" prio=10 tid=0x00007f512c051800 nid=0x2f9d runnable 

"GC task thread#0 (ParallelGC)" prio=10 tid=0x0000000041414800 nid=0x2f95 runnable 

"GC task thread#1 (ParallelGC)" prio=10 tid=0x00007f512c001000 nid=0x2f96 runnable 

"GC task thread#2 (ParallelGC)" prio=10 tid=0x00007f512c002800 nid=0x2f97 runnable 

"GC task thread#3 (ParallelGC)" prio=10 tid=0x00007f512c004800 nid=0x2f98 runnable 

"GC task thread#4 (ParallelGC)" prio=10 tid=0x00007f512c006800 nid=0x2f99 runnable 

"GC task thread#5 (ParallelGC)" prio=10 tid=0x00007f512c008000 nid=0x2f9a runnable 

"GC task thread#6 (ParallelGC)" prio=10 tid=0x00007f512c00a000 nid=0x2f9b runnable 

"GC task thread#7 (ParallelGC)" prio=10 tid=0x00007f512c00c000 nid=0x2f9c runnable 

"VM Periodic Task Thread" prio=10 tid=0x00007f512c089000 nid=0x2fa4 waiting on condition 

Очевидно, что большинство потоков связаны с обработкой памяти: есть 8 потоков коллектора мусора, а также детектор низкой памяти. Finalizer и Reference Handler звучат так, как будто они также задействованы в управлении памятью.

C2 CompilerThread0/1 почти наверняка связано с компиляцией "точно вовремя".

VM Periodic Task Thread объясняется здесь: Что такое "Периодическая задача задачи VM" ?

Что касается точной цели остальных потоков, я не уверен.

Ответ 2

Я сделал этот снимок экрана с помощью jvisualvm. Запуск потоков (в затмении):

Java Threads

Запуск той же программы, что и файл *.jar; есть только 4 потока демона и 1 поток в реальном времени.

Ответ 3

Это может не ответить на вопрос, но, по крайней мере, помочь понять, что происходит. Чтобы получить точный образец потоков, получите форму списка в своем приложении. (Вместо инструментов отладки.)

JVM без инструментария

  • Тема: main
  • Тема: Обработчик ссылок
  • Тема: Диспетчер сигналов
  • Тема: Attach Listener
  • Тема: Финализатор

JVM w/Instrumentation (jconsole)

  • Тема: main
  • Тема: Время ожидания соединения сервера JMX 12
  • Тема: RMI TCP Connection (1) -10.1.100.40
  • Тема: RMI TCP Connection (2) -10.1.100.40
  • Тема: Финализатор
  • Тема: Обработчик ссылок
  • Тема: RMI Scheduler (0)
  • Тема: Диспетчер сигналов
  • Тема: RMI TCP Accept-0
  • Тема: Attach Listener

Эксперимент

  • Выполните следующий код
  • Запустите jconsole и подключитесь к этому jvm
public class JVM {
  public static void main(String... args) throws InterruptedException {
    for (java.util.Enumeration<?> e = System.getProperties().propertyNames(); e.hasMoreElements();) {
      String prp = (String) e.nextElement();
      if (prp.startsWith("java.vm") || prp.startsWith("os.")) {
        System.out.format("[%s]=%s%n", prp, System.getProperty(prp));
      }
    }
    java.text.DateFormat df = new java.text.SimpleDateFormat("HH:mm:ss.SSS");
    for(;;) {
      System.out.format("%s Sampling current threads...%n", df.format(new java.util.Date()));
      java.util.Map<Thread, StackTraceElement[]> stacks = Thread.getAllStackTraces();
      System.out.format("> Thread Count: %d%n", stacks.size());
      for (java.util.Map.Entry<Thread, StackTraceElement[]> entry : stacks.entrySet()) {
        Thread thread = entry.getKey();
        StackTraceElement[] stack = entry.getValue();
        System.out.format("> Thread: %s%n", thread.getName());
        // Throwable t = new Throwable("Thread: " + thread.getName());
        // t.setStackTrace(stack);
        // t.printStackTrace(System.out);
      }
      java.util.concurrent.TimeUnit.SECONDS.sleep(10);
    }
  }
}

Выход

[java.vm.version]=16.2-b04
[java.vm.vendor]=Sun Microsystems Inc.
[java.vm.name]=Java HotSpot(TM) Client VM
[java.vm.specification.name]=Java Virtual Machine Specification
[os.arch]=x86
[java.vm.specification.vendor]=Sun Microsystems Inc.
[os.name]=Windows XP
[os.version]=5.1
[java.vm.specification.version]=1.0
[java.vm.info]=mixed mode, sharing
14:03:49.199 Sampling current threads...
> Thread Count: 5
> Thread: main
> Thread: Reference Handler
> Thread: Signal Dispatcher
> Thread: Attach Listener
> Thread: Finalizer
14:03:59.200 Sampling current threads...
> Thread Count: 10
> Thread: main
> Thread: JMX server connection timeout 12
> Thread: RMI TCP Connection(1)-10.1.100.40
> Thread: RMI TCP Connection(2)-10.1.100.40
> Thread: Finalizer
> Thread: Reference Handler
> Thread: RMI Scheduler(0)
> Thread: Signal Dispatcher
> Thread: RMI TCP Accept-0
> Thread: Attach Listener

Ответ 4

Когда вы обычно запускаете Java-программу, она запускается на виртуальной машине. Некоторые из потоков, которые вы видите, для VM - либо для работы виртуальной машины, либо для повышения эффективности (потоки компилятора - когда найден потенциальный кандидат на оптимизацию (называемый "горячим местом" ), эти потоки будут скомпилируйте его с байт-кода Java на машинный код для платформы, на которой работает JVM).

Большинство других потоков предназначены для управления памятью. Есть так много, чтобы дать лучший пользовательский интерфейс (интерфейс/интерфейс будет зависать в течение меньшего времени, если сборка мусора заканчивается быстрее).