2

I'm struggling with something stupidly simple...

My real project was suffering of an unknown problem for ages, them i decided to create a very simple test and i got scared with the results...

Here is the test:

ExecutorService t = new ThreadPoolExecutor(10, 20, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(600));
        for (int i = 0; i < 100; i++) {
            final int i1 = i;
            t.execute(new Runnable() {

                @Override
                public void run() {
                    while (true) {
                        System.out.println(i1);
                        try {
                            Thread.sleep(5000);
                        }
                        catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }

                }
            });
        }

I'm creating a thread pool with 10 core thread plus 20 maximumPoolSize then i give to it 100 threads which will simple print a fixed number each...

MY HUMBLE STUPID THOUGHT WAS:

The pool has 10 threads, will print 0-9 randomly then after some instans 10 extra threads will be created and pool will print from 0-19 randomly

This is kind of obvious to me since maxSize is 20 it should accept 20 tasks in worst case...

but the result was 0-9 being printed forever

the question is: What is the point of maximumPoolSize if the extra threads are never scheduled for execution?

Rafael Lima
  • 3,079
  • 3
  • 41
  • 105
  • 5
    Not stupid at all, that would've been the logical way to do that, sun chose to use `maximumPoolSize` only when the queue is full instead, see [here](https://stackoverflow.com/questions/12236694/how-does-maximumpoolsize-of-threadpoolexecutor-works) for more details – Oleg Dec 25 '18 at 03:40
  • I would NEVER guess it, it's tottally counter intuitive... it seems like they are "willing" blow quere capacity when obvious desire would be maximize throuput... can you point me one advantage of sun way? – Rafael Lima Dec 25 '18 at 04:03
  • 1
    Only Doug Lea really knows(if he remembers). The idea is from his [PooledExecutor](http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/PooledExecutor.java) class from 1998, CPUs and the jvm were very different back then and perhaps using additional threads as a last resort when the queue is full made sense. The last comment [here](https://coderanch.com/t/464571/java/Doug-Lea-PooledExecutor-won-grow) explains it in a kind of a sensible way. – Oleg Dec 25 '18 at 04:28

2 Answers2

3

As correclty pointed by @Oleg, the pool works fine but there is an implementation detail i wasn't aware.

The extra threads will only be created if the task queue is FULL

this article explains better: http://www.bigsoft.co.uk/blog/2009/11/27/rules-of-a-threadpoolexecutor-pool-size

Take this example. Starting thread pool size is 1, core pool size is 5, max pool size is 10 and the queue is 100.

Sun's way: as requests come in threads will be created up to 5, then tasks will be added to the queue until it reaches 100. When the queue is full new threads will be created up to maxPoolSize. Once all the threads are in use and the queue is full tasks will be rejected. As the queue reduces so does the number of active threads.

User anticipated way: as requests come in threads will be created up to 10, then tasks will be added to the queue until it reaches 100 at which point they are rejected. The number of threads will rename at max until the queue is empty. When the queue is empty the threads will die off until there are corePoolSize left.

So Java waits to last second before your queue blow out to create a new thread...

Rafael Lima
  • 3,079
  • 3
  • 41
  • 105
1

Yes, As per @Oleg and the implementation you tried:

new ThreadPoolExecutor(10, 20, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue(600));

Here, 10 is the corePoolSize - means Jvm will create new thread for new task for first 10 tasks. and other tasks will be added to the queue until queue is getting full (600 tasks).

20 is the maxPoolSize - JVM can create max 20 threads. Means if there are already 10 task/thread is running and queue is full with 600 pending tasks and if one more new request/task is arriving in queue then JVM will create new thread up to 20 (total threads=previous 10 + new 10);

new ArrayBlockingQueue(600) = is a total queue size - it can queue 600 tasks in it.

once all 20 threads are running and if new task is arriving then that new task will be rejected.

[FROM DOC] Rules for creating Threads internally by SUN:

  • If the number of threads is less than the corePoolSize, create a new Thread to run a new task.
  • If the number of threads is equal (or greater than) the corePoolSize, put the task into the queue.
  • If the queue is full, and the number of threads is less than the maxPoolSize, create a new thread to run tasks in.
  • If the queue is full, and the number of threads is greater than or equal to maxPoolSize, reject the task.

Hope it's helpful.

Vebbie
  • 1,669
  • 2
  • 12
  • 18