Java thread pool: What happens to idle threads - java

I am trying to understand multi-threading in Java. I have written the following java program to test thread pool.
public class ThreadPoolTest
{
public static void main(String[] args)
{
ExecutorService executorService = Executors.newFixedThreadPool(5);
for( int i = 0; i < 3; i++ )
{
executorService.submit(new Task(i+1));
}
executorService.shutdown();
}
public static class Task implements Runnable
{
private int taskId;
public Task(int id)
{
taskId = id;
}
#Override
public void run() {
System.out.println("Executing task " + taskId + " performed by " + Thread.currentThread().getName() );
try
{
Thread.sleep(3000);
}
catch(InterruptedException interruptEx)
{
System.out.println(Thread.currentThread().getName() + " got interrupted ");
}
System.out.println("Finished executing task " + taskId );
}
}
}
The main thread creates executor which creates 5 threads and I have submitted only 3 tasks. After that I am shutting down the executor. When I run the code, the main thread finishes before the child threads. In this case, does JVM takes care of the child threads?
Also I have created a thread pool with 5 threads, but submitted only 3 tasks. Will the remaining 2 threads are terminated when the main thread exits?
What actually happens when the executor service is shutdown?

From the doc of ExecutorService#shutdown():
Initiates an orderly shutdown in which previously submitted tasks are
executed, but no new tasks will be accepted.
This means that all the Jobs you submitted to the Executor will finish on their own time without interrupting or "hurrying" them, and the executor will finish up the worker threads properly, but neither will the service accept new Jobs, nor will it terminate instantly.
Compare ExecutorService#shutdownNow(), which will try to terminate as quickly as possible.

The Worker threads that the executor creates are inner classes that have a reference back to the executor itself. (They need it to be able to see the queue, runstate, etc!) Running threads are not garbage collected, so with each Thread in the pool having that reference, they will keep the executor alive until all threads are dead. If you don't manually do something to stop the threads, they will keep running forever and your JVM will never shut down.
In case of 5 threads where 3 tasks are only spawned, 2 unused thread will never be started but there references will remain as it is until shutdown is called in finalize() or all the live threads completes there execution.
Following is the comment from JAVA Docs:
A pool that is no longer referenced in a program AND has no remaining threads will be >shutdown automatically. If you would like to ensure that unreferenced pools are reclaimed >even if users forget to call shutdown(), then you must arrange that unused threads >eventually die, by setting appropriate keep-alive times, using a lower bound of zero core >threads and/or setting allowCoreThreadTimeOut(boolean).

In this case, does JVM takes care of the child threads?
The OS manages threads and determines when they are run.
Also I have created a thread pool with 5 threads, but submitted only 3 tasks. Will the remaining 2 threads are terminated when the main thread exits?
No, the threads run until you shut them down.
What actually happens when the executor service is shutdown?
The threads are interrupted and no new tasks will start. However, if you have a task which ignores interrupts it could keep running indefinitely.
When the last non-deamon thread stops the shutdown hook (if any) are triggered.

does JVM takes care of the child threads
JVM only complete its execution after completing all daemon threads. If you are creating your as non daemon then it will wait till all non daemon threads complete.
Will the remaining 2 threads are terminated when the main thread exits
Threads will be created in ondemand mode. So here 3 threads only created not 5.
What actually happens when the executor service is shutdown
Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted. Invocation has no additional effect if already shut down.
This method does not wait for previously submitted tasks to complete execution. Use awaitTermination to do that.

Related

ExecutorService should wait until batch of taksk is finished before starting again

The Problem:
I am parsing a large log file (around 625_000_000 lines) and saving it into the database.
public class LogScheduler {
static int fileNumber = 1;
public Importer(IRequestService service) {
this.service = service;
}
#Override
public void run() {
try {
service.saveAll(getRequestListFromFile("segment_directory/Log_segment_"+fileNumber+".txt"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
The method that runs this thread is:
public void scheduledDataSave() throws InterruptedException {
int availableCores = Runtime.getRuntime().availableProcessors();
String directory = "segment_directory";
int filesInDirectory = Objects.requireNonNull(new File(directory).list()).length;
ExecutorService executorService = Executors.newFixedThreadPool(availableCores);
for (int i = 1; i <= filesInDirectory; i++) {
executorService.execute(new Importer(service));
}
executorService.shutdown();
}
Inserting the Thread.sleep(); method after the executorService.execute(new Importer(service)); sleeps after the execution of every thread, and not 8 threads like it should since they are in the Executorservice
And I have no idea why that happens since it should not behave like that.
From what I understand, the ExecutorService should run 8 threads in parallel, finish them, sleep, and start the pool again.
How to "sleep" after every 8 threads?
Sleeping the thread submitting tasks does not sleep the submitted tasks
Your question is not clear, but apparently centers around your expectation that adding a Thread.sleep after each call to executorService.execute would sleep all the threads of the executor service.
for ( int i = 1 ; i <= filesInDirectory ; i++ ) {
executorService.execute( new Importer( service ) ); // Executor service assigns this task to one of the background threads in its backing pool of threads.
Thread.sleep( Duration.ofMillis( 100 ).toMillis() ) ; // Sleeping this thread doing the looping. *Not* sleeping the background threads managed by the executor service.
}
Your expectation in incorrect.
That Thread.sleep is sleeping the thread doing the for loop.
The executor service has its own backing pool of threads. Those threads are not affected by a Thread.sleep is some other thread. Those background threads will only sleep if you call Thread.sleep within the code running on each of those threads.
So you are feeding the first task to the executor service. The executor service immediately dispatches that work to one of its backing threads. That task is immediately executed (if a thread is available immediately, and not otherwise occupied by previous tasks).
After assigning that task, your for loop sleeps for a hundred milliseconds, in this example code shown here. While the for loop is asleep, no further tasks are being assigned to the executor service. But while the for loop is asleep, the submitted task is executing on a background thread. That background thread is not sleeping.
Eventually, your for loop thread wakes, assigns a second task, and goes back to sleep. Meanwhile the background thread executes at full speed ahead.
So sleeping the thread submitting tasks does not sleep tasks already submitted.
Waiting for submitted tasks to complete
Your title asks:
ExecutorService should wait until batch of taksk is finished before starting again
After submitting your tasks, call shutdown and awaitTermination on your executor service. After those calls, your code blocks, waiting until all the submitted tasks are are completed/canceled/failed.
ExecutorService executorService = Executors.newVirtualThreadExecutor() ;
… submit tasks to that executor service …
executorService.shutdown() ;
executorSerivce.awaitTermination() ; // At this point, the flow-of-control blocks until the submitted tasks are done.
System.out.println( "INFO - Tasks on background threads are done. " + Instant.now() );
I would suggest using the ExecutorService#submit method rather than ExecutorService#execute method. The difference is that the first method returns a Future object. You can collect these Future objects as you submit tasks to the executor service. After the shutdown & awaitTermination, you can examine your collection of Future objects to check their completion status.
Project Loom
If Project Loom succeeds, such code will be a bit simpler and more clear. Experimental builds of Project Loom technology are available now, based on early-access Java 17. The Loom team seeks feedback now.
With Project Loom, ExecutorService becomes AutoCloseable. This means we can use try-with-resources syntax to automatically call a new close method on ExecutorService. This close method first blocks until all the tasks are completed/canceled/failed, then shuts down the executor service. No need to call shutdown nor awaitTermination.
By the way, Project Loom also bring virtual threads (fibers). This is likely to dramatically increase the performance of your code because it involves much blocking for storage i/o and database access.
try (
ExecutorService executorService = Executors.newVirtualThreadExecutor() ;
)
{
… submit tasks to that executor service …
}
// At this point, with Project Loom technology, the flow-of-control blocks until the submitted tasks are done.
// Also, the `ExecutorService` is automatically closed/shutdown by this point, via try-with-resources syntax.
System.out.println( "INFO - Tasks on background threads are done. " + Instant.now() );
With Project Loom, you can collect the returned Future objects in the same manner as discussed above to examine completion status.
You have other issues in your code. But you've not disclosed enough to address them all.
How to "sleep" after every 8 threads?
So if you are doing something like this, then it isn't doing what you think.
for (int i = 1; i <= filesInDirectory; i++) {
executorService.execute(new Importer(service));
Thread.sleep(...);
}
This causes the thread which is starting the background jobs to sleep and does not affect the running on each of the jobs. I believe what you are missing is to wait for the thread-pool to finish:
executorService.shutdown();
executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
This waits for all of the jobs in the thread-pool to complete before continuing.
One more thing. I use executorService.submit(...) versus execute(...). Here's a description of their difference. For me, one additional difference is that any exceptions thrown by tasks run with execute(...) cause the running thread to terminate and possibly be restarted. With submit(...) it allows you to get that exception if needed and stops the threads from having to be respawned unnecessarily.
If you explain a bit more about what you are trying to accomplish, we should be able to help.

Scheduled Executor Service with single thread

I have a sample code for Scheduled Executor Service, taken from Oracle's site. It creates a ScheduledExecutorService with core pool size o 1. It does 2 jobs: First it starts a repeated task executed at fixed intervals and then it kills the same task and the service itself after a delay.
ScheduledExecutorService scheduledService = Executors.newScheduledThreadPool(1);
//This will keep executing the task at fixed interval
ScheduledFuture<?> futureTask = scheduledService.scheduleAtFixedRate(new RepeatedTask(), initialDelay, interval, TimeUnit.SECONDS);
//A future task is returned which can be used to cancel the execution after sometime
//Here we will cancel our repeated task after 100 seconds
scheduledService.schedule(new TaskStopper(futureTask, scheduledService), 100, TimeUnit.SECONDS);
The repeated task code:
public class RepeatedTask implements Runnable{
int count = 0;
#Override
public void run() {
count++;
System.out.println(count + ". Beep");
}
}
The stop task
#Override
public void run() {
mFutureTask.cancel(true);
System.out.println("Task stopped");
mExecutorService.shutdownNow();
boolean shutDown = mExecutorService.isShutdown();
if(shutDown) {
System.out.println("Executor shutdown");
}else {
System.out.println("Executor not shutdown");
}
}
I want to understand, how does it work with a single thread in the thread pool.
Since our executor service performs two tasks and starts them both almost at the same time,
shouldn't we have 2 threads i.e. a ScheduledExecutorService with core pool size of 2.
It works fine though. I just want to understand why it works fine with a single thread.
For any thread pool (including ScheduledThreadPool), number of threads can be less than number of tasks. Thread pools internally have a queue of tasks, in which a task will have to wait if no thread is available to execute the task.
In your example, at t=100 seconds, two tasks need to be executed. Since only one thread is available, it executes the first task (while second one waits in the queue). Once the first task is complete, the thread picks the second task from the queue and completes it.
You could print out the thread id in both the tasks and can verify that they are indeed being processed by the same thread.
Edit:
So basically the task scheduled at fixed interval is executed multiple times with fixed intervals in between. During these intervals, our single thread in the pool is idle and is able to pick other tasks for execution. That's how a single thread executes both the tasks.

Is blocking main method in Java always bad?

We have an application that's continuously running. Nothing much goes on in the main method except initializing a few background threads. The background threads process socket events as they occur. Apart from the time the socket events are being processed, app remains in the idle state.
Main
Start Thread 1 -> while(socket connection 1 is good) -> process events
Start Thread 2 -> while(socket connection 2 is good) -> process events
Start Thread 3 -> while(socket connection 3 is good) -> process events
Start Thread 4 -> while(socket connection 4 is good) -> process events
while (true); // block main thread from exiting. Otherwise, periodic GC calls kills the app.
As the primary function of my app is to process events and there is not foreground tasks as such. Does blocking main thread is bad in my case? What are some other alternates?
the main thread is just the first thread, and as such is not different from any other thread. If you block it, it means waste of memory occupied by this thread (about 1MB) and nothing more. So I would just return from the main method, if there is no job for this thread.
I noticed a comment in your code: block main thread from exiting. Otherwise, periodic GC calls kills the app. The comment is wrong. GC calls cannot kill the application. I suspect other threads are started in daemon mode, and so the enclosing process does not wait for them to finish.
If you describe in more details when the whole process must end, we could make more sensible advises.
Since your main thread does busy waiting it will require thread scheduler to it (main thread) into list of scheduled threads. And if your machine where you are running your app has less then 4 CPUs then your event processing threads will suffer.
There are a lot of other ways to block your main thread without busy waiting. Thread.join() as mentioned above is one of them. You can also use Future.get(), or ExecutorService.awaitTermination() if you use high level concurrency objects.
Yes, it's a bad design. Use a ExecutorService and add the threads to it.
Blocking in the main method (or from any other thread) should be avoided. The problem you are running into – how to create some threads and keep the JVM running until those threads finish – can be solved in better ways.
If you create a new Thread and call setDaemon(false), then you won't need to do anything with sleeping or waiting. By setting the thread to be non-daemon, the JVM will stay running until that thread completes. From the Javadoc:
The Java Virtual Machine exits when the only threads running are all daemon threads.
Here's an example thread class that tries to sleep for 2 seconds, then prints out a message:
class ExampleThread extends Thread {
#Override
public void run() {
try {
sleep(2000);
System.out.println("done sleeping");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
If you call it like this – by setting daemon to false – you will first see
output thread started, followed by 2 seconds of nothing, then output done sleeping.
public static void main(String[] args) {
ExampleThread t = new ExampleThread();
t.setDaemon(false);
t.start();
System.out.println("thread started");
}
If you replace t.setDaemon(false) with this t.setDaemon(true) – so that the new thread is in fact a daemon thread – then you will see output thread started followed by immediate JVM termination.

How to shutdown the ThreadServiceExecutor where the number of threads is not initially known [duplicate]

This question already has answers here:
ExecutorService, how to wait for all tasks to finish
(16 answers)
Closed 5 years ago.
I am in the process of writing a code where whenever a folder is encountered it is supposed to start a new thread. The code looks like,
p
ublic void diff(File x,File y){
ThreadPoolExecutor executor=new ThreadPoolExecutor(10,30,2000,unit,BlockingQueue<Runnable> queue)
if(x.isDirecotry && y.isDirectory){
Runnable thread=new DThread(x,y);
Future<?> result=executor.submit(thread);
if(result.isDone()){
LOGGER.debug(thread.toString()+"has completed");
}
I am using ThreadPoolExecutor for this purpose. If I shutdown the ThreadPoolExecutor then it will not take up any new Threads. But there is a possibility of new threads starting after starting. If I do not shutdown the ThreadPoolExecutor then all the threads are executed but in the end the JVM is not terminating.
Please help how can I shutdown the threadPool only when all the threads are executed so that the JVM gets terminated. Also suggest if there is better way of implemention of thread pool.I want to use thread pool so that I can use threads from the pool instead of creating new thread everytime.
The things that you are submitting should not be threads (subtypes of Thread). They should be simple tasks: implementations of Runnable or Callable.
The way to shutdown the executor is to call shutdown() or shutdownNow() on it. The javadoc summary says:
void shutdown() -
Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted.
List<Runnable> shutdownNow() - Attempts to stop all actively executing tasks, halts the processing of waiting tasks, and returns a list of the tasks that were awaiting execution.
The latter attempts to stop the tasks by interrupting them. However, if the task code does not check for interrupts, it will run to completion. (It also stops accepting new tasks.)
It sounds like shutdown() does what you want to do.
The problem lies in the fact where should I place the shutdown method.
You call it when you want to start shutting down.
Because there is a possibility that new threads may be coming after shutdown is being called.
Stop calling them threads. They are tasks.
Any tasks that are submitted after shutdown() has been called are rejected.
My question is how can I check whether all the tasks have finished executing and only then call shutdown. If I call with the initiation of each task then it will not allow new tasks later on.
The correct time to call shutdown() is when your application has finished submitting tasks to the executor.
Maybe your conceptual problem is the scoping of the executor service. Your example code seems to show that each call to diff is creating a new service object. That means that you would have lots of independent thread pools ... and no reuse of threads. What you should really do is to create a "global" thread pool and have multiple calls to diff submit tasks to the same pool.

Interrupt Runnable that takes hours

I have a ThreadPoolExecutor:
ThreadPoolExecutor service = new ThreadPoolExecutor(N_THREADS, N_THREADS, 0L, TimeUnit.MILLISECONDS, blockingQueue, rejectedExecutionHandler);
The service executes threads implementing the Runnable interface. Each thread processes a file on disk. I found that after several hours, two threads (or cores depending on what htop shows in Linux) were running and had been running for 13 hours. What's even worse is that the remaining cores showed no activity as if they were waiting for the two threads to complete.
Questions:
1 - I have read a lot on how this problem may be resolved but nothing conclusive. As far as I can work out, you CANNOT stop a Runnable using the ThreadPoolExecutor because it is an independent thread that just runs. Using the Future framework:
Future<?> f = f.get(submittedtask,XX)
allows you to set a timeout and fetch the future result, but get blocks all the threads effectively making the implementation serial. Is it possible to interrupt a Runnable after a given time using the threadpoolexecutor, get the thread back to the pool so it can pickup a new task and carry on.
2 - My big concern is why, using htop, I see two threads/cores running and no other core/thread are running despite many tasks are still waiting to execute (i.e. there are many files left to process). Any insight?
You could create a second scheduled thread pool to which you would submit cancellation tasks for each of the returned Futures. Each of these tasks after a given timeout would check if it's associated Future is done and if not, cancel it. Cancellation would trigger thread interruption, so you might need to support it in your tasks by checking the interrupted flag: Thread.interrupted().
The size of this second thread pool could be minimal, i.e. 1 as this job takes minimum of CPU time.
Code example:
ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
...
while(...){
final Future<?> f = pool.submit(...);
service.schedule(new Runnable() {
#Override
public void run() {
if(!f.isDone()){
f.cancel(true);
}
}
}, 1, TimeUnit.MINUTES);
}
service.awaitTermination(1, TimeUnit.MINUTES);
service.shutdown();
You can tell a thread that you wish to interrupt:
An interrupt is an indication to a thread that it should stop what it is doing and do something else.
You can interrupt your thread with Future.cancel(true). It's in your responsibility to implement the Runnable in a manner that it obeys that wish by checking its Thread.interrupted() state.
In order to see details about process thread run:
ps -eLf | grep <PROCESS_PID>
Since htop shows you the running processes list, where each process has at least one thread.

Categories