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);
}
}
If you want to process exceptions thrown by the task, then it is generally better to use Callable rather than Runnable . If Callable. call() throws an exception, this will be wrapped in an ExecutionException and thrown by Future.
ExecutorService must be shutdown explicitly to reclaim the resources (CPU & Memory) occupied by threads which have already finished their job but still exist.
The executor service creates and maintains a reusable pool of threads for executing submitted tasks. The service also manages a queue, which is used when there are more tasks than the number of threads in the pool and there is a need to queue up tasks until there is a free thread available to execute the task.
This is settled by the documentation:
When a new task is submitted in method
execute(java.lang.Runnable)
, and fewer thancorePoolSize
threads are running, a new thread is created to handle the request, even if other worker threads are idle. If there are more thancorePoolSize
but less thanmaximumPoolSize
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>());
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);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With