Search code examples
javamultithreadingconcurrencyrunnableexecutorservice

If you submit one runnable to an executor service with multiple threads, will multiple threads execute that runnable?


I'm having a hard time understanding how ExecutorService works in Java 8. I was trying to understand some of the code on this website: https://crunchify.com/hashmap-vs-concurrenthashmap-vs-synchronizedmap-how-a-hashmap-can-be-synchronized-in-java/

Particularly at the end where he tests the runtimes of the different maps. This is the code:

public class CrunchifyConcurrentHashMapVsSynchronizedMap {

public final static int THREAD_POOL_SIZE = 5;

public static Map<String, Integer> crunchifyHashTableObject = null;
public static Map<String, Integer> crunchifySynchronizedMapObject = null;
public static Map<String, Integer> crunchifyConcurrentHashMapObject = null;

public static void main(String[] args) throws InterruptedException {

    // Test with Hashtable Object
    crunchifyHashTableObject = new Hashtable<String, Integer>();
    crunchifyPerformTest(crunchifyHashTableObject);

    // Test with synchronizedMap Object
    crunchifySynchronizedMapObject = Collections.synchronizedMap(new HashMap<String, Integer>());
    crunchifyPerformTest(crunchifySynchronizedMapObject);

    // Test with ConcurrentHashMap Object
    crunchifyConcurrentHashMapObject = new ConcurrentHashMap<String, Integer>();
    crunchifyPerformTest(crunchifyConcurrentHashMapObject);

}

public static void crunchifyPerformTest(final Map<String, Integer> crunchifyThreads) throws InterruptedException {

    System.out.println("Test started for: " + crunchifyThreads.getClass());
    long averageTime = 0;
    for (int i = 0; i < 5; i++) {

        long startTime = System.nanoTime();
        ExecutorService crunchifyExServer = Executors.newFixedThreadPool(THREAD_POOL_SIZE);

        for (int j = 0; j < THREAD_POOL_SIZE; j++) {
            crunchifyExServer.execute(new Runnable() {
                @SuppressWarnings("unused")
                @Override
                public void run() {

                    for (int i = 0; i < 500000; i++) {
                        Integer crunchifyRandomNumber = (int) Math.ceil(Math.random() * 550000);

                        // Retrieve value. We are not using it anywhere
                        Integer crunchifyValue = crunchifyThreads.get(String.valueOf(crunchifyRandomNumber));

                        // Put value
                        crunchifyThreads.put(String.valueOf(crunchifyRandomNumber), crunchifyRandomNumber);
                    }
                }
            });
        }

        // Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted. Invocation
        // has no additional effect if already shut down.
        // This method does not wait for previously submitted tasks to complete execution. Use awaitTermination to do that.
        crunchifyExServer.shutdown();

        // Blocks until all tasks have completed execution after a shutdown request, or the timeout occurs, or the current thread is
        // interrupted, whichever happens first.
        crunchifyExServer.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);

        long entTime = System.nanoTime();
        long totalTime = (entTime - startTime) / 1000000L;
        averageTime += totalTime;
        System.out.println("500K entried added/retrieved in " + totalTime + " ms");
    }
    System.out.println("For " + crunchifyThreads.getClass() + " the average time is " + averageTime / 5 + " ms\n");
}

}

So in the crunchifyPerformTest class, he's starting an ExecutorService with 5 threads and then submitting 5 different runnables with 500k reads and writes to the hashmap each time? Will the executor service automatically have 5 threads executing each runnable?


Solution

  • No. Each Runnable is executed on exactly one thread. This means that all Runnables will be executed in parallel, because the number of Runnables matches the number of available threads.

    You could also submit 6 Runnables. In this case 5 of them would be executed in parallel and as soon as one Runnable has finished execution, the sixth one will be executed.

    By the way, I think the docs are quite clear about the behaviour of this ExecutorService.