Question

If I run long lasting tasks Executor never starts new threads if first task is not finished. Could someone please help me to understand why and how can I fix this?

import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.junit.Test;

public class TestExecutor {

    @Test
    public void test() throws InterruptedException {
        ExecutorService checkTasksExecutorService = new ThreadPoolExecutor(1, 10,
                100000, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>());

        for (int i = 0; i < 20; i++) {
            checkTasksExecutorService.execute(new Runnable() {

                public  void run(){
                    try {
                        System.out.println(Thread.currentThread().getName() + "   running!");
                        Thread.sleep(10000);
                    } catch (Exception e) {
                    }

                }
            });
        }

        Thread.sleep(1000000);
    }
}
Was it helpful?

Solution 2

This behavior is due to the logic within the ThreadPoolExecutor where new threads are added if there is a failure to offer a task to the queue. Your queue is not bounded, so it effectively means that we will never grow above the core pool size and up to the maximum pool size.

Try this example to see the difference:

   ExecutorService checkTasksExecutorService = new ThreadPoolExecutor(1, 10,
                100000, TimeUnit.MILLISECONDS,
                new SynchronousQueue<Runnable>());

        for (int i = 0; i < 10; i++) {
            checkTasksExecutorService.execute(new Runnable() {

                public void run() {
                    try {
                        System.out.println(Thread.currentThread().getName() + "   running!");
                        Thread.sleep(1000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                }
            });
        }

        //Thread.sleep(1000000); //instead this use following

//stop accepting new tasks
        checkTasksExecutorService.shutdown();

while (!checkTasksExecutorService.isTerminated()) {
            Thread.sleep(100);
        }

OTHER TIPS

This is settled by the documentation:

When a new task is submitted in method execute(java.lang.Runnable), and fewer than corePoolSize threads are running, a new thread is created to handle the request, even if other worker threads are idle. If there are more than corePoolSize but less than maximumPoolSize threads running, a new thread will be created only if the queue is full.

So, to achieve the behavior you want, either increase the corePoolSize or give the executor service a non-growable queue, like this:

ExecutorService checkTasksExecutorService = new ThreadPoolExecutor(1, 20,
    100000, TimeUnit.MILLISECONDS,
    new SynchronousQueue<Runnable>());

The javadoc of ExecutorService.execute() says:

Executes the given command at some time in the future. The command may execute in a new thread, in a pooled thread, or in the calling thread, at the discretion of the Executor implementation.

This is reinforced by the javadoc for ThreadPoolExecutor.execute(), which says:

The task may execute in a new thread or in an existing thread.

But the reason is explained in the source comments for ThreadPoolExecutor.execute() which says:

If a task can be successfully queued, then we are done

and a bit later

If we cannot queue the task, then we try to add a new thread

Since your queue is unbounded, further tasks can be queued, so new threads are not created to execute the following tasks.

More threads are created only if the task can not be queued.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top