What determines the number of threads a Java ForkJoinPool creates?

前端 未结 5 1707
北恋
北恋 2020-12-02 11:00

As far as I had understood ForkJoinPool, that pool creates a fixed number of threads (default: number of cores) and will never create more threads (unless the a

5条回答
  •  谎友^
    谎友^ (楼主)
    2020-12-02 11:48

    There're related questions on stackoverflow:

    ForkJoinPool stalls during invokeAll/join

    ForkJoinPool seems to waste a thread

    I made a runnable stripped down version of what is happening (jvm arguments i used: -Xms256m -Xmx1024m -Xss8m):

    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.ForkJoinPool;
    import java.util.concurrent.RecursiveAction;
    import java.util.concurrent.RecursiveTask;
    import java.util.concurrent.TimeUnit;
    
    public class Test1 {
    
        private static ForkJoinPool pool = new ForkJoinPool(2);
    
        private static class SomeAction extends RecursiveAction {
    
            private int counter;         //recursive counter
            private int childrenCount=80;//amount of children to spawn
            private int idx;             // just for displaying
    
            private SomeAction(int counter, int idx) {
                this.counter = counter;
                this.idx = idx;
            }
    
            @Override
            protected void compute() {
    
                System.out.println(
                    "counter=" + counter + "." + idx +
                    " activeThreads=" + pool.getActiveThreadCount() +
                    " runningThreads=" + pool.getRunningThreadCount() +
                    " poolSize=" + pool.getPoolSize() +
                    " queuedTasks=" + pool.getQueuedTaskCount() +
                    " queuedSubmissions=" + pool.getQueuedSubmissionCount() +
                    " parallelism=" + pool.getParallelism() +
                    " stealCount=" + pool.getStealCount());
                if (counter <= 0) return;
    
                List list = new ArrayList<>(childrenCount);
                for (int i=0;i

    Apparently when you perform a join, current thread sees that required task is not yet completed and takes another task for himself to do.

    It happens in java.util.concurrent.ForkJoinWorkerThread#joinTask.

    However this new task spawns more of the same tasks, but they can not find threads in the pool, because threads are locked in join. And since it has no way to know how much time it will require for them to be released (thread could be in infinite loop or deadlocked forever), new thread(s) is(are) spawned (Compensating for joined threads as Louis Wasserman mentioned): java.util.concurrent.ForkJoinPool#signalWork

    So to prevent such scenario you need to avoid recursive spawning of tasks.

    For example if in above code you set initial parameter to 1, active thread amount will be 2, even if you increase childrenCount tenfold.

    Also note that, while amount of active threads increases, amount of running threads is less or equal to parallelism.

提交回复
热议问题