Welcome readers, this blog is all about threading in Java. After reading this, you would be comfortable enough to program multi-threaded applications. Here, you will learn about java threads, thread pools and the concept of java future.
Java Threading: The Beginning
In Java, the concept of multi-threading was there from the first version itself. In Java, you can implement threading by implementing Runnable
interface and proving the thread functionality in the overridden method void run()
. Here’s an example of implementing the runnable interface. I’m using lambda expression for overriding the run()
method.
Here above, the main thread is asynchronously running with 10 other threads. In main
thread, whenever start()
method is called, it will execute the overridden run()
method in a different thread. After thread completes its task by executing the code specified in the run()
method, it will get killed. Here’s another example which shows that if the parent thread dies, the child threads will also die.
In the above example, when the main thread dies, all its child thread dies without completing their execution.
In Java, every thread corresponds to one operating system thread. If we create multiple threads to improve multi-tasking, it would be a very heavy task as creating a thread in itself is an expensive task. To know more about thread creation, you can refer to thread creation overhead.
Welcome to Thread Pool
Now, as we know that creating a thread in itself is an expensive task, we can replace it with creating a thread pool instead with a fixed number of threads. Thread pool came into java in 1.5v in which we can submit tasks to the thread pool which are executed by the threads. A sample program to show the working of a thread pool.
In the above program, we have created a thread pool using ExecutorService
class which has created a Fixed Thread Pool which contains 2 threads. The service.execute()
method is used to submit tasks to the thread pool. The thread pool internally uses the blocking queue where the tasks are submitted. The threads inside the pool perform two tasks:
- Fetch the task from the blocking queue
- Execute the fetched task.
Types of Thread Pool
1.Fixed Thread Pool: The number of threads in this pool are fixed.
//Creation of Fixed thread pool with 4 threads
ExecutorService service = Executors.newFixedThreadPool(4);
//Task Submission in the thread pool
service.execute(Runnable r);
2. Cached Thread Pool: The number of threads are not fixed and are created if a task is not able to find a free thread available for its execution.
//Creation of Cached thread pool
ExecutorService service = Executors.newCachedThreadPool();
//Task Submission in the thread pool
service.execute(Runnable r);
3. Scheduled Thread Pool: Here, only those tasks are submitted which are to be triggered after a certain delay.
//Creation of Scheduled Thread Pool
ScheduledExecutorService service = Executors.newScheduledThreadPool(10);
//Task Submission in the thread pool
//1. Submitted task to run only once after 2 seconds delay
service.schedule(Runnable r,2,TimeUnit.SECONDS);
//2. Submitted task to run repeatedly every 2 seconds after a delay of 4 seconds
service.scheduleAtFixedRate(Runnable r,4,2,SECONDS);
//3. Submitted task to run repeatedly 4 seconds after the previous task completes after a delay of 5 seconds
service.scheduleWithFixedDelay(Runnable r,5,4,SECONDS);
4. Single Threaded Executor: It is a single threaded pool which executes the tasks in sequence and if any exception occurs while execution and the thread dies, it will recreate the thread and continue with the execution of remaining tasks.
//Creation of Cached thread pool
ExecutorService ex = Executors.newSingleThreadExecutor();
//Task Submission in the thread pool
service.execute(Runnable r);
Futures
Till now, whatever task we have performed in the threads does not return anything as the run()
method returns void
. But what if the task needs to return a value. Here comes the Callable<> interface which has an abstract method T call()
which returns T
type value.
To submit a callable task, we need to call service.submit(Callable c)
and the value returned by this method is held by a Future<>
variable.
Future is a placeholder for the value which will arrive in the future, depends on the time the call()
method takes. Future placeholder is returned by the ThreadPool.
//This return an integer future value 10.
Future<Integer> future = service.submit(()->{
return 10;
});
When the callable’s call method finishes its execution, it returns the value of type Future
. To fetch the result, we need to call get()
method. It is a blocking function which means it will block the caller thread until the result is received from the future. This limitation of future was overcame by CompletableFuture
which I will cover in my next blog.
Some other important methods of Future<>
are:
cancel(boolean):
This will cancel the task if the thread pool has not started executing the task, else it won’t make any effect.
isCancelled():
It is used to check if the task is cancelled or not.
isDone():
It returns a boolean value to check if the task is executed or not. It doesn’t matter whether it is executed successfully or not.
References:
After going through the contents, now you’ll be familiar with the concept of threading, thread pool, and future in java. For any queries, feel free to contact me at yatharth.sharma@knoldus.in.
Thank you for sticking to the end. If you like this blog, please do show your appreciation by giving thumbs ups and share this blog and give me suggestions on how I can improve my future posts to suit your needs. Follow me to get updates on different technologies.