Reputation: 4606
In the code below no matter what I set as the max value of i, the total number of threads never crosses 13. What thread pool does it use? Where can I find its default settings?
public static void main(String[] args) {
// write your code here
for (int i = 0; i <= 5; i++) {
System.out.println("kick off" + i);
CompletableFuture.runAsync(() -> {
try {
Thread.sleep(1000);
System.out.println(java.lang.Thread.activeCount());
}
catch (Exception e) {
System.out.println("error");
}
});
}
System.out.println(java.lang.Thread.activeCount());
try {
Thread.sleep(10000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
Upvotes: 9
Views: 15874
Reputation: 25903
It is determined either by your system settings or based on your current amount of processors.
From the documentation of CompletableFuture:
All
async
methods without an explicit Executor argument are performed using theForkJoinPool.commonPool()
(unless it does not support a parallelism level of at least two, in which case, a new Thread is created to run each task). This may be overridden for non-static methods in subclasses by defining methoddefaultExecutor()
. [...]
From the documentation of ForkJoinPool#commonPool():
Returns the common pool instance. This pool is statically constructed; [...]
From the documentation of the class ForkJoinPool itself:
The parameters used to construct the common pool may be controlled by setting the following system properties:
java.util.concurrent.ForkJoinPool.common.parallelism
- the parallelism level, a non-negative integerjava.util.concurrent.ForkJoinPool.common.threadFactory
- the class name of a ForkJoinPool.ForkJoinWorkerThreadFactory. The system class loader is used to load this class.java.util.concurrent.ForkJoinPool.common.exceptionHandler
- the class name of a Thread.UncaughtExceptionHandler. The system class loader is used to load this class.java.util.concurrent.ForkJoinPool.common.maximumSpares
- the maximum number of allowed extra threads to maintain target parallelism (default 256).
If no thread factory is supplied via a system property, then the common pool uses a factory that uses the system class loader as the thread context class loader.
From there on, we have to check the actual source code. From ForkJoinPool.java#L3208:
common = AccessController.doPrivileged(new PrivilegedAction<>() {
public ForkJoinPool run() {
return new ForkJoinPool((byte)0); }});
From the constructor at ForkJoinPool.java#L2345:
// [...]
String pp = System.getProperty("java.util.concurrent.ForkJoinPool.common.parallelism");
// [...]
if (pp != null)
parallelism = Integer.parseInt(pp);
// [...]
if (parallelism < 0 && // default 1 less than #cores
(parallelism = Runtime.getRuntime().availableProcessors() - 1) <= 0)
parallelism = 1;
// [...]
int n = (parallelism > 1) ? parallelism - 1 : 1;
n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16;
n = (n + 1) << 1;
// [...]
this.workQueues = new WorkQueue[n];
And there you go. It is determined either by your system settings or based on your current amount of processors.
Supposed you did not set anything for java.util.concurrent.ForkJoinPool.common.parallelism
, lets quickly do the math for the code:
parallelism
starts with -1
in that case, so we have
if (parallelism < 0 && // default 1 less than #cores
(parallelism = Runtime.getRuntime().availableProcessors() - 1) <= 0)
parallelism = 1;
Let us suppose you have 8 cores on your machine. So you execute parallelism = Runtime.getRuntime().availableProcessors() - 1
which assigns 7
to parallelism
. You do not enter the if
, so we continue.
Next up we have
int n = (parallelism > 1) ? parallelism - 1 : 1;
Which subtracts one of it, so n = 6
.
Then
n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16;
n = (n + 1) << 1;
Results in 16
.
What this does is basically subtracting 2
and then going to the next power of 2
and then doubling it.
So if you have 6
cores, it goes to 4
, then to 8
and then times 2
, so 16
.
So why do you get 13
? I suppose you have 4
or 5
processors, so the pool would use 8
threads. However, you are measuring the total amount of threads used by Java in total.
System.out.println(java.lang.Thread.activeCount());
And Java probably uses around 13 - 8 = 5
threads for other "standby" things right now.
Upvotes: 18