Search code examples
javaparallel-processingmulticoreexecutorservice

Why does a SingleThreaded Executor service use 4 cores?


I have the following code which uses a single-threaded executor service, but running it uses all the 4 cores on my machine (each core around 80% usage in average).

The question is why is this happening? And I am not interested here in finding Fibonacci really!

public class MainSimpler {
    static int N=35;
    static AtomicInteger result = new AtomicInteger(0), pendingTasks = new AtomicInteger(1);
    static ExecutorService executor;

    public static void main(String[] args) {
        executor = Executors.newSingleThreadExecutor(); 
        long before = System.currentTimeMillis();
        System.out.println("Fibonacci "+N+" is ... ");
        executor.submit(new FibSimpler(N));
        waitToFinish();
        System.out.println(result.get());
        long after = System.currentTimeMillis();        
        System.out.println("Duration: " + (after - before) + " milliseconds\n");
    }

    private static void waitToFinish() {
        while (0 < pendingTasks.get()){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        executor.shutdown();
    }
}



class FibSimpler implements Runnable {
    int N;
    FibSimpler (int n) { N=n; }

    @Override
    public void run() {
        compute();
        MainSimpler.pendingTasks.decrementAndGet();
    }

    void compute() {
        int n = N;
        if (n <= 1) {
            MainSimpler.result.addAndGet(n);
            return;
        }
        MainSimpler.executor.submit(new FibSimpler(n-1));
        MainSimpler.pendingTasks.incrementAndGet();
        N = n-2;
        compute();  // similar to the F/J counterpart
    }
}

This is related to another question of mine.


Solution

  • Just tried on my machine and I get 35% total CPU usage (4 cores). Note that you have at least 2 threads in your program (the main thread and the executor thread).

    However, if I increase N to 100, the CPU usage goes up to 90+% because a lot of time is spent in Full GCs (and I was running with 2GB of heap).

    So it looks like your single thread gets too busy and tasks start accumulating, waiting for being executed.

    You could try to run the code with the following JVM parameters: -XX:+PrintGC

    The output on my machine looks like:

    [GC 511999K->465632K(1962688K), 1.0286778 secs]
    [GC 977632K->922984K(1962688K), 1.1999209 secs]
    [GC 1434984K->1407984K(1962688K), 1.2421900 secs]
    [Full GC 1407984K->1373358K(1962688K), 9.8320408 secs]
    [Full GC 1885358K->1822040K(1962688K), 7.5170472 secs]
    [Full GC 1877375K->1870974K(1962688K), 7.6635945 secs]
    [Full GC 1877374K->1876550K(1962688K), 7.6705722 secs]
    [Full GC 1877374K->1877272K(1962688K), 7.8381579 secs]
    [Full GC 1877372K->1877357K(1962688K), 8.6095022 secs]