Simple Java example runs with 14 threads. Why?
Asked Answered
O

4

15

The following trivial Java code:

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

Runs using 14 threads. I know that theres some GC thread running in the background, but what are the others for? Why are there so many threads? I'm on Gentoo Linux with Java 1.6.0_26. Compiling with Eclipse's compiler or javac doesn't make a difference(Running it in Eclipse in debug mode adds 3 more threads to it, but that's probably justified).

Ona answered 8/10, 2011 at 18:26 Comment(6)
How are you running your code? If you are running it from within an IDE, could it be that your IDE itself is written (and running) in Java?Trot
I'm curious - how are you determining that it runs 14 threads?Snick
What makes you think there's 14 threads?Trenttrento
To those asking how to find out the number of running threads: jstack or jvisualvm (there exist other tools as well).Twum
I run the code with "java Main" after running "javac Main.class" or with Ctrl+F11 in Eclipse. I use "ps aux -L" which gives you an NLWP column to see the number of threads.Ona
The compiler doesn't determine the number of threads, only the JVM.Congregational
T
15

My JVM (1.6.0_26) spawns even more threads by default. Most have pretty descriptive names that hint at their purpose:

"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 

Clearly, most of the threads have to do with memory handling: there are 8 garbage collector threads, plus the low memory detector. Finalizer and Reference Handler sound like they are also involved in memory management.

C2 CompilerThread0/1 almost certainly have to do with just-in-time compilation.

VM Periodic Task Thread is explained here: What is the "VM Periodic Task Thread"?

As to the exact purpose of the remaining threads, I am not sure.

Twum answered 8/10, 2011 at 18:31 Comment(4)
Nice, I guess this explains a lot. But how did you get this output?Ona
The finalizer thread is the one that runs the finalize code of garbage collected objects in the background. Now I'm really intrigued what the reference handler thread is doing - let's see if we find something about that ;)Lysol
@Voo, I assume the Reference handle cleans up things like WeakReferences.Whirl
@MarkRotteveel I read up some time ago about WeakReferences, ReferenceQueues and alike, but I must admit I didn't pay too close attention to the fine details. But wouldn't the GC just add a reference to the queue (if existing) when clearing it and be done with it? What would we need the additional thread for, since no code is executed automatically there? (since we have to poll the queue ourselves in the code).Lysol
U
5

I made this Screenshot using jvisualvm. Running threads (in eclipse):

Java Threads

Running the same program as *.jar file; there are only 4 daemon threads and 1 live thread running.

Ungava answered 8/10, 2011 at 18:29 Comment(2)
Running a .jar file didn't make any difference for me. Your output looks like you run it in debug mode, is that correct? How did you produce your .jar file?Ona
A exported the program as executable *.jar file in eclipse and executed it via command line with java -jar file.jar. Screenshot was from running it in eclipse with Run as > Java Application.Ungava
C
5

This may not answer the question, but at least help understand what's going on. To get an accurate sample of the threads, get the list form within your app. (Instead of from the debugging tools.)

JVM w/o Instrumentation

  • Thread: main
  • Thread: Reference Handler
  • Thread: Signal Dispatcher
  • Thread: Attach Listener
  • Thread: Finalizer

JVM w/ Instrumentation (jconsole)

  • 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

Experiment

  1. Execute the following code
  2. Launch jconsole and connect to that 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);
    }
  }
}

Output

[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
Curiosa answered 8/10, 2011 at 19:12 Comment(0)
H
0

When you typically run a Java Program, it runs on a virtual machine. Some of the threads you see are for the VM -- either for the functioning of the VM or to increase the efficiency (the compiler threads -- when a potential candidate for optimization is found (called a "Hot spot"), these threads will compile it from Java Byte code to machine code for the platform on which the JVM is running).

Most of the other threads are for memory management. There are so many to give a better user experience (the UI / interface will hang for lesser time if garbage collection finishes faster).

Hambletonian answered 9/10, 2011 at 9:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.