Introduction
Long running tasks need a special way of handling which user have not to wait until these tasks finished, our get benefit of CPU power and parallel processing long running tasks to finished faster.
What is a Thread?
A thread is a path of program execution, and JVM allows that multiple paths/threads to work concurrently and not interfere each other.
Working with threads in Java
As we said before a thread is a path of exaction, and any piece of logic have to run as part of thread as below image.
The Main thread is responsible for executing logic inside main method and execution have to go through line by line and not to move to next until finishing current one. As above image there is a long running task there, and if Main thread is responsible for executing this logic the result will not be shown until this method finish execution, it maybe this method not affect the result at all and making user wait until this method finishes is bad practice.
Create your own thread
As part of soliton you can define your own thread and attach your long running logic in and start this path, so we need 2 things:
- Logic that will run through this path.
- Thread to act as path.
By this there is sperate thread executing the task and main thread continuing in his path and printing the result. But inline implementation or anonymous class is code smell and we have to avoid it, instead in OOP paradigm you can do this
Or you are free to use functional paradigm with Runnable functional interface and lambda expression as below
Void is not enough
If you notice that Runnable interface has void as return type for run method which can not return a value from that processing, but what if we need a value from that side processing. In this case you have to use Callable interface as below.
Callable interface has a generic type that you can assign any data type as a return type, but unfortunately you can't assign a callable interface to Thread class, instead you have to use what called ExecutorService class as below
As above we declared ExecutorService that will manage thread execution and will get the result after the thread is finished, and we said that we want this executor to manage up to only 1 thread not more, then by using submit() we attach the task we want to execute to the executor. As per our requirement that we asked to run this long running task in separate path and not to block that main thread and also we need a return value from this task. What java did is provided to us Future interface, Java tells us that I will take this task and execute it in separate thread, Then take this Future reference, when the task finishes you will find your result in, and to access the result you can use get() method.
if you called get() method and the thread not finish the execution yet, the main thread will be blocked until the long running task thread finished its' execution and because of this get() method throws ExecutionException
ExecutorService for parallel processing
You can also use executor service for parallel processing on huge data as below
As above we have 3 messages and ExecutorService with 3 threads in its' pool, by constructing 3 task one for each message the executor will assign one task to each thread in his pool and let it start the processing and whenever any one finishes it's execution you can get its' result
Here we have same number of threads with same number of tasks but if we have larger number of tasks ExecutorService will assign first 3 tasks to its' threads and put the rest of tasks on hold until any of threads finish and assign to another one and so on
ForkJoin Framework
ForkJoin framework is works also as parallel processing but with different approach, it using recursive approach to split the tasks until to reach a predefined batch/size and then start to assign this batch to thread to work on.
you can go with more details and implementation examples here
Resources
IF YOU LIKED THE POST, THEN YOU CAN BUY ME A COFFEE, THANKS IN ADVANCE.
Top comments (2)
One thing you may want to add to this is proper use of Thread.interrupt().
Namely, in a long running task you should check *interrupted() * and act accordingly. And never ignore InterruptException in your code.
One of the answers here: stackoverflow.com/questions/206919...
Explains this in detail.
Proper handling of this can make your thread interruptible which is very useful if you have an out of control task you want to stop. Or if you want to reprioritize it if it's taking too long.
Thanks for sharing!