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.
Related
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.
I am using an ExecutorService with a fixedThreadPool. I create threads by implementing the Runnable interface. In the run() method, I am calling a time consuming function (let's say Thread.sleep() for now) and finally add an element to a thread safe CopyOnWriteArrayList. I am submitting threads in a for-loop. At the end of the for-loop I shutdown the ExecutorService and await termination.
However, the number of elements in the list does not turn out to be the same as the number of loop-iterations. Where is my mistake in concurrency thinking?
Here is a code example for this problem:
public class TestProgram {
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(4);
CopyOnWriteArrayList<String> stringList = new CopyOnWriteArrayList<String>();
for (int i = 0; i < 1000; i++) {
executor.submit(new myThread(stringList));
}
executor.shutdown();
executor.awaitTermination(10, TimeUnit.SECONDS);
System.out.println(Integer.toString(stringList.size()));
}
}
class myThread implements Runnable {
CopyOnWriteArrayList<String> stringList;
public myThread(CopyOnWriteArrayList<String> stringList) {
this.stringList = stringList;
}
public void run() {
String string = new String("test");
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(myThread.class.getName()).log(Level.SEVERE, null, ex);
}
stringList.add(string);
}
}
You're just not giving it enough time to complete. If you want to execute this serially you would need 1000 * 100 milliseconds, which is 100 seconds. You are running it with four threads, so divide that by 4 and you get 25 seconds. You only wait 10 seconds to complete. Increase that to 26 seconds just to be safe and you should see your result.
The ExecutorService#awaitTermination will wait the N number of seconds to complete, if it doesn't complete it will simply return out and continue the execution. To prove my point check the return value
System.out.println(executor.awaitTermination(10, TimeUnit.SECONDS));
The better solution here, is to use a new CountDownLatch(1000), have each Runnable task countDown after it adds to the list and finally have the main thread await completion.
The documentation of ExecutorService.shutdown says the following:
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.
This means that you indicate your ExecutorService that it must stop it's services. Thus, this method sets a flag which indicates that the ExecutorService will end soon, which allows the main thread to returns from this method without problems.
ExecutorService.awaitTermination, moreover, reads as follows:
Blocks until all tasks have completed execution after a shutdown
request, or the timeout occurs, or the current thread is interrupted,
whichever happens first.
This means that the main thread will be blocked inside the method, where it will only be returned when the tasks sent to ExecutorService finish. In both cases, the developer intends to end the ExecutorService function. But with awaitTermination, the developer is saying ExecutorService should be terminated regardless of their tasks have been carried out or not.
As each task takes at least 100 milliseconds to complete, no one will possibly be completed because ExecutorService has a tolerance of only 10 milliseconds for completion of all it's tasks.
There is no point in calling shutdown and awaitTermination at the same time (or preceded by another). According to your code, shutdown has no effect. If you want your tasks to become completed, and that ExecutorService is terminated without caring if your main thread will continue, just use shutdown. If you do not want your main thread to be blocked, and simply want to end with ExecutorService, use shutdownNow.
If, on the other hand, you want your main thread to wait for the execution of your tasks without a certain time to be specified, you may have to use Java Synchronizers. Some of Java Synchronizers are as follow:
Latches
FutureTasks
Semaphores
Barriers
For your case, I believe you can use CountDownLatch. Make a new CountDownLatch object have the number of tasks running on your ExecutorService. As they are completed, the count is decreased, and so, your main thread can expect completion and continue after all.
I hope you have understood and you can do what you want. If you have further questions, the documentation of CountDownLatch demonstrates perfectly how you can synchronize tasks. Good luck.
In that code snippet one issue will be there.
executor.awaitTermination(10, TimeUnit.SECONDS);
Here it will wait for 10 seconds after that it will break.
You will try following snippet.
while (true) {
if(executor.awaitTermination(10, TimeUnit.SECONDS))
break;
}
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.
I am using following code snippet in our code.
ExecutorService executor = Executors.newFixedThreadPool(4);
while(loop 50 times){
//In the extreme case I will have 50 threads and only 4 will be active and remaining are in queue
MyThread myThread = new MyThread();
executor.execute(myThread);//Each Thread process 100,000 records and put in a file
}
executor.shutdown();
while (!executor.isTerminated()) {
}
Here are my questions:
It is hanging at second while loop. What might be the reason?
Is there any way to terminate Entire thread pool after certain interval?
Can I terminate a thread after certain time interval?
Please help me in fixing this.
1.It is hanging at second while loop. What might be the reason?
The reason for hanging could be because of very few threads compared to the amount of records that needs to be processed and stored in file. If each thread is supposed to process 100,000 records and put in file then 50 thread tasks shared by 4 threads will have to process 5,000,000 records with 50 files. So better to increase the number of threads and check. Also note down time taken by each thread to effectively measure if you are reducing the time taken overall by increasing the number of fixed pool threads.
2.Is there any way to terminate Entire thread pool after certain interval?
Yes below code shows that:-
executor.shutdown();
executor.awaitTermination(60, TimeUnit.SECONDS); // blocks/waits for certain interval as specified
executor.shutdownNow(); // Forcefully terminate entire thread pool after the above time.
3.Can I terminate a thread after certain time interval?
Yes if effectively the reason for terminating a thread is to stop what task it is doing. To achieve this we need to get a reference to the future and wait conditionally for period of time before we forcefully cancel the task and interrupt the thread carrying out the task.
Map<String, Future> tasks = new HashMap<String, Future>();
while(i++ < 50){
//In the extreme case I will have 50 threads and only 4 will be active and remaining are in queue
Thread myThread = new Thread();
tasks.put("Thread"+i ,executor.submit(myThread));//Each Thread process 100,000 records and put in a file
}
// say you want to terminate Thread2 after 60 seconds
Future thread2Task = tasks.get("Thread2");
thread2Task.get(60, TimeUnit.SECONDS);
thread2Task.cancel(true); // boolean whether you want to interrupt the thred forcefully
ExecutorServise will have a pool of Threads to execute your Runnable tasks, you defined the size of the pool to be 4, I would change that to be the number of cpus in the machine:
int threadCount = Runtime.getRuntime().availableProcessors();
ExecutorService executor = Executors.newFixedThreadPool(threadCount);
Also, it appears that you are sending Threads to the executor to execute them in one of the available threads in it's pool, It's redundant, you might change your MyThread to a Runnable task.
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.