There is a queue of tasks, created as follows:

LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(); ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(maximumPoolSize, maximumPoolSize, 50000L, TimeUnit.MILLISECONDS, queue); 

The maximumPoolSize value is 200. During operation, a large number of threads (more than a thousand) hit the queue , but the value returned by the threadPoolExecutor.getActiveCount() method is always less than or equal to 100. For example, the values ​​of threadPoolExecutor.getActiveCount() and queue.size() logged in the following way:

 logger.debug("АктивныС ΠΏΠΎΡ‚ΠΎΠΊΠΈ: " + threadPoolExecutor.getActiveCount() + ". Π’ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ " + queue.size() + " ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ²."); 

and as a result we get the following picture:

 АктивныС ΠΏΠΎΡ‚ΠΎΠΊΠΈ: 1. Π’ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ 0 ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ². АктивныС ΠΏΠΎΡ‚ΠΎΠΊΠΈ: 2. Π’ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ 0 ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ². АктивныС ΠΏΠΎΡ‚ΠΎΠΊΠΈ: 3. Π’ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ 0 ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ². АктивныС ΠΏΠΎΡ‚ΠΎΠΊΠΈ: 4. Π’ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ 0 ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ². АктивныС ΠΏΠΎΡ‚ΠΎΠΊΠΈ: 5. Π’ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ 0 ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ². ... АктивныС ΠΏΠΎΡ‚ΠΎΠΊΠΈ: 86. Π’ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ 0 ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ². АктивныС ΠΏΠΎΡ‚ΠΎΠΊΠΈ: 87. Π’ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ 1 ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ². АктивныС ΠΏΠΎΡ‚ΠΎΠΊΠΈ: 88. Π’ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ 1 ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ². АктивныС ΠΏΠΎΡ‚ΠΎΠΊΠΈ: 89. Π’ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ 1 ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ². АктивныС ΠΏΠΎΡ‚ΠΎΠΊΠΈ: 90. Π’ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ 1 ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ². ... АктивныС ΠΏΠΎΡ‚ΠΎΠΊΠΈ: 99. Π’ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ 1 ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ². АктивныС ΠΏΠΎΡ‚ΠΎΠΊΠΈ: 100. Π’ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ 1 ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ². АктивныС ΠΏΠΎΡ‚ΠΎΠΊΠΈ: 100. Π’ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ 2 ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ². АктивныС ΠΏΠΎΡ‚ΠΎΠΊΠΈ: 100. Π’ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ 3 ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ². АктивныС ΠΏΠΎΡ‚ΠΎΠΊΠΈ: 100. Π’ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ 4 ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ². ... АктивныС ΠΏΠΎΡ‚ΠΎΠΊΠΈ: 100. Π’ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ 1874 ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ². АктивныС ΠΏΠΎΡ‚ΠΎΠΊΠΈ: 100. Π’ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ 1875 ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ². АктивныС ΠΏΠΎΡ‚ΠΎΠΊΠΈ: 100. Π’ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ 1876 ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ². АктивныС ΠΏΠΎΡ‚ΠΎΠΊΠΈ: 100. Π’ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ 1877 ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ². АктивныС ΠΏΠΎΡ‚ΠΎΠΊΠΈ: 100. Π’ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ 1878 ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ². АктивныС ΠΏΠΎΡ‚ΠΎΠΊΠΈ: 100. Π’ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ 1879 ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ². АктивныС ΠΏΠΎΡ‚ΠΎΠΊΠΈ: 100. Π’ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ 1880 ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ². АктивныС ΠΏΠΎΡ‚ΠΎΠΊΠΈ: 100. Π’ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ 1881 ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ². АктивныС ΠΏΠΎΡ‚ΠΎΠΊΠΈ: 100. Π’ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ 1882 ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ². АктивныС ΠΏΠΎΡ‚ΠΎΠΊΠΈ: 100. Π’ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ 1883 ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ². 

The documentation says that the threadPoolExecutor.getActiveCount() method returns an approximate number of threads with actively running tasks. But why the maximum threshold of this approximate value here is maximumPoolSize / 2?

PS This logs are not from my computer, I could not reproduce this situation - in my case the number of active threads is 200, as expected. Could this be a dependence on the number of processors / number of processor cores / any software configuration?

  • Let me leave a comment that is not directly related to the question itself: it’s not the threads that are thrown off, but the tasks. - etki
  • @Etki, thanks, this is a typo - Ksenia
  • one
    I think if you don’t give the full code, there is very little chance that someone will answer you. You have a fixed-size pool, such a case is described in the ThreadPoolExecutor documentation. Look at the mini benchmark , which helps determine the optimal size of the pool and queue. - enzo

1 answer 1

"There is a task queue, created as follows: ... new ThreadPoolExecutor (maximumPoolSize, maximumPoolSize, .."

Are you sure that maximumPoolSize is one variable and it has one value? I believe that the reason is that corePoolSize is equal to 100, and maximumPoolSize is equal to 200 and the following happens with you?

When a new thread is added to the pool, it performs the following actions sequentially:

  1. Checks whether the limit of the threads specified by the variable corePoolSize is reached; if you can still start the stream, it starts it. If the number of threads is equal to or greater than corePoolSize, proceed to the next step.
  2. Checks if the queue is not full and if there is still space in it adds the stream to it. If the queue is full, go to the next step.
  3. Attempts to increase the number of working threads to the value of maximumPoolSize. If you can add another stream, then it is added to it and the task is started. If the number of working threads is equal to maximumPoolSize, then a java.util.concurrent.RejectedExecutionException exception is thrown or a program deflection interceptor is called.

In your case, since the queue grows without restrictions to the third step, the algorithm never passes. But you can β€œchange” the order of steps 2 and 3. To do this, you need to create a queue in which we override the offer method called by ThreadPoolExecutor so that it always returns false (the queue is full). Now we need to define our own RejectedExecutionHandler interceptor. In the interceptor, we add the received stream to the queue. An example of the above in the form of code:

 LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable> (100){ public boolean offer(Runnable e) {return false;} }; ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(100, 200, 1, TimeUnit.MINUTES, queue, new RejectedExecutionHandler() { public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { try { executor.getQueue().put(r); } catch (InterruptedException e) { e.printStackTrace(); } } });