DEV Community

Cover image for Tackle long running tasks with Java threads
Sameh Muhammed
Sameh Muhammed

Posted on

Tackle long running tasks with Java threads


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.

Image description

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.

Image description

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:

  1. Logic that will run through this path.
  2. Thread to act as path.

Image description

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

Image description

Or you are free to use functional paradigm with Runnable functional interface and lambda expression as below

Image description

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.

Image description

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

Image description

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

Image description

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

Image description

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



Buy Me A Coffee

Top comments (2)

aminmansuri profile image

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:

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.

smuhammed profile image
Sameh Muhammed

Thanks for sharing!