Once more into the breach of microbenchmarking:
import java.math.BigInteger; import java.util.LinkedList; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicLong; public class SillyThroughputTest { private static final int MAX_TASKS = 100; private static final int MAX_LOOP = 100000; private static AtomicLong foundPrimes = new AtomicLong(); public static void main(String[] args) { List taskList = new LinkedList(); for (int i = 0; i < MAX_TASKS; i++) { Runnable task = buildTask(); taskList.add(task); } // runEachTaskInNewThread(taskList); runEachTaskInFixedSizeExecutor(taskList); } private static void runEachTaskInFixedSizeExecutor(List taskList) { long started = System.currentTimeMillis(); ExecutorService executor = Executors.newFixedThreadPool(2); List results = new LinkedList(); while (!taskList.isEmpty()) { Runnable runnable = taskList.remove(0); Future future = executor.submit(runnable); results.add(future); } for (Future future : results) { try { future.get(); } catch (InterruptedException e) { } catch (ExecutionException e) { } } long stopped = System.currentTimeMillis(); long durationMillis = stopped - started; System.out.println("Took " + (double) durationMillis / 1000d + " s in total, counting " + foundPrimes.get() + " primes"); executor.shutdown(); } private static void runEachTaskInNewThread(List taskList) { long started = System.currentTimeMillis(); runEachTaskInANewThreadAndWaitForCompletion(taskList); long stopped = System.currentTimeMillis(); long durationMillis = stopped - started; System.out.println("Took " + (double) durationMillis / 1000d + " s in total, counting " + foundPrimes.get() + " primes"); } private static void runEachTaskInANewThreadAndWaitForCompletion(List taskList) { List workers = new LinkedList(); while (!taskList.isEmpty()) { Runnable runnable = taskList.remove(0); Thread thread = new Thread(runnable); workers.add(thread); } for (Thread thread : workers) { thread.start(); } for (Thread thread : workers) { try { thread.join(); } catch (InterruptedException e) { // go on to the next one } } } private static Runnable buildTask() { return new Runnable() { public void run() { long startMillis = System.currentTimeMillis(); for (int i = 0; i < MAX_LOOP; i++) { BigInteger bigInteger = new BigInteger("" + i); if (bigInteger.isProbablePrime(10)) { foundPrimes.incrementAndGet(); } } } }; } }
Using a fixed pool of 2 threads:
Took 43.594 s in total, counting 959201 primes (99% cpu)
Using a thread per task (100 in this case):
Took 92.5 s in total, counting 959200 primes (65% cpu)