CodersTea - Sip & Learn
Java

Do not buy, reuse the old: ThreadPool

 0

 0

 22

By CodersTea-Team

 On Feb 8, 2020 at 06:47 pm

 

Introduction

Hey tea lovers. Did you ever try to drive a car, ride the bikes, and sail a boat simultaneously? I bet you did, at least in programming. If not check out how on my previous post “Drive a car, ride the bikes, and sail a boat simultaneously”. Well, I am talking about multithreading. Threads are really powerful things that let you multitask. But if there is heaven there is hell. There are multiple headaches. Creating, Managing and the most important one is coordination between them if your app needs it. But in this, we will be more focused on creating it.

The Hell

If you ever tried to drive multiple cars simultaneously you may have been buying it for each ride. Just replace the word car with thread and buying with creating and driving with running. you get the picture. Sure it gets your work done pretty fast but at which cost? multiple Thread creation is a very expensive process and it can delay the actual process which you wanted to avoid in the first place. In java threads are mapped to system-level threads, so over numbering them can empty your resources. So how will you avoid these multiple new thread creation? Using the already existing threads. But how? Just sip your tea and read. You can find the code on github here or the full project here

Recycling is good for the environment: Thread pool

Threadpool in java offers the solution to our problem of thread cycle overhead or resource trashing by reusing the threads.

How does the pooling work

What is pooling by the way? In a simpler word, combining resources for sharing. Examples can be your Uber pool, printer sharing in your office, Dynamic Host Configuration Protocol (DHCP), JDBC connection pooling and many more.

In thread or any pooling, you collect N number of thread or resource in one place. You get the pick one thread from it, use it and you put it back into the pool after completing your work. Well, its the simplest way of explaining it. There can be certain scenarios like all the resources are busy when you went to pick it up, you wait or add one if possible and use it up to the maximum limit of the pool. after waiting you come back again and get the thread that has been put back after use by another user. Let us now jump to the ThreadPooling in java.

ThreadPool continued

Now that we know about the pooling, let us jump to the actual working of thread pooling in java. To use the Threadpool in Java, Java provides a framework called Executor Framework which is an interface called Executor and its subinterface ExecutorService and the classes implementing them. Don’t worry its not another dependency. It is in the package java.util.concurrent. The Executor contains only one abstract method called execute(Runnable task). Through this, you can execute your tasks. Tasks are just Runnable objects.

public interface Executor {    void execute(Runnable command);}

ExecutorService

ExecutorService is a subinterface of the Executor interface. It is a pro version you can say. It has multiple methods that give us more control over tasks. You can see there are multiple methods or functions you can use. To execute a task you can use the execute(Runnable task) method. There is a method submit(..) which returns a Future<T> that shows your result of the task. Future basically says that “I may or may not have the value right now but it could be available in the future if the task is completed and produces some result”. We will talk about it in another post. But how can you create the object or thread pool of ExecutorService? Via Executors.

Executors

Executors is a kind of factory/utility class for the ExecutorService. It creates the objects of ExecutorServices. There are various ways you can create different types of pools.

Method Description
newSingleThreadExecutor() Creates a single thread.
newFixedThreadPool(int size) Creates a fixed size thread pool.
newCachedThreadPool() Creates a thread pool that creates new threads as needed, but will reuse previously constructed threads if they are available

In case of newFixedThreadPool(int size) and newSingleThreadExecutor() the threads need to wait if the size is full and no thread is available to use. But in case of newCachedThreadPool() new task doesn’t need to wait if the thread is not available.

The Example

Let us rewrite the example of “Drive a car, ride the bikes, and sail a boat simultaneously” using the thread pool. In the example, you have Boats, cars, and bikes. In the previous one, we had created a new thread for each vehicle. Now we will use and understand the working and use case of the thread pool creation methods in the above table.

Make sure the shutdown the thread pool after all the task has been assigned or it will be the program will not stop.

The tasks: Car, Bike and the Boat

public class ThreadPool {    static void pring5Times(String statement) {        for (int i = 0; i < 5; i++) {            System.out.println(statement + i);            try {                Thread.sleep(100);            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}class Car1 implements Runnable {    @Override    public void run() {        ThreadPool.pring5Times("I am driving a Car on road ");    }}class Bike1 implements Runnable {    @Override    public void run() {        ThreadPool.pring5Times("I am riding a Bike on road ");    }}class Boat1 implements Runnable {    @Override    public void run() {        ThreadPool.pring5Times("I am Sailing the boat on sea ");    }}

These are the Runnable objects we will be using. Let us see the each funcitons one by one.

Executors.newSingleThreadExecutor()

A single thread will be passed to each task. o the result will be a sequential execution.

static void newSingleThreadExecutor() {    System.out.println("Running Executors.newSingleThreadExecutor()");    ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();    singleThreadPool.execute(new Car1());    // bike and boat will wait till car driving is completed.    singleThreadPool.execute(new Bike1());    singleThreadPool.execute(new Boat1());    //make sure to shitdown.    singleThreadPool.shutdown();}

Output

Running Executors.newSingleThreadExecutor()I am driving a Car on road 0I am driving a Car on road 1I am driving a Car on road 2I am driving a Car on road 3I am driving a Car on road 4I am riding a Bike on road 0I am riding a Bike on road 1I am riding a Bike on road 2I am riding a Bike on road 3I am riding a Bike on road 4I am Sailing the boat on sea 0I am Sailing the boat on sea 1I am Sailing the boat on sea 2I am Sailing the boat on sea 3I am Sailing the boat on sea 4

 

As you can see threads are running one by one since there is only one thread to be shared.

Executors.newFixedThreadPool(int size)

We will create the thread pool of size 2. In this case Bike and Car. 2 threads will run in parallel. The third task needs to wait until the thread is available.

static void newFixedThreadPool(){    System.out.println("Running Executors.newFixedThreadPool(2)");    ExecutorService fixedSizeThreadPool = Executors.newFixedThreadPool(2);    fixedSizeThreadPool.execute(new Car1());    fixedSizeThreadPool.execute(new Bike1());    // this time Since threadpool only has 2 thread,    // Boat will wait till car driving and bike riding is completed.    fixedSizeThreadPool.execute(new Boat1());    fixedSizeThreadPool.shutdown();}

Output

Running Executors.newFixedThreadPool(2)I am driving a Car on road 0I am riding a Bike on road 0I am driving a Car on road 1I am riding a Bike on road 1I am driving a Car on road 2I am riding a Bike on road 2I am driving a Car on road 3I am riding a Bike on road 3I am driving a Car on road 4I am riding a Bike on road 4I am Sailing the boat on sea 0I am Sailing the boat on sea 1I am Sailing the boat on sea 2I am Sailing the boat on sea 3I am Sailing the boat on sea 4

 

Bike and Car ran simultaneously but the boat needed to wait since only 2 threads were available.

 

Executors.newCachedThreadPool()

This will create the thread if a new task is assigned and for the task no thread is available. So all the threads could be run simultaneously since the size ay vary.

static void newCachedThreadPool(){    System.out.println("Running Executors.newCachedThreadPool()");    ExecutorService chachedThreadPool = Executors.newCachedThreadPool();    chachedThreadPool.execute(new Car1());    chachedThreadPool.execute(new Bike1());    chachedThreadPool.execute(new Boat1());    chachedThreadPool.shutdown();}

Output

Running Executors.newCachedThreadPool()I am driving a Car on road 0I am riding a Bike on road 0I am Sailing the boat on sea 0I am driving a Car on road 1I am riding a Bike on road 1I am Sailing the boat on sea 1I am driving a Car on road 2I am riding a Bike on road 2I am Sailing the boat on sea 2I am driving a Car on road 3I am riding a Bike on road 3I am Sailing the boat on sea 3I am driving a Car on road 4I am riding a Bike on road 4I am Sailing the boat on sea 4

 

As you can see all you were able to drive, ride and sail simultaneously.

That’s it for this tea break. You can find the code on github here or the full project here. In the next post on concurrency, we will talk about Future and CompletableFuture.

   javabestpracticesconcurrencyconnectionpoolingcuttingfunctionalprogrammingfunctionalprogramminginstallationjavajava8jdbclatestjdkmultithreadingnamingconventionreflectionapistreamapi

About Contributer

Questions / Comments


Comments

Be the first to comment on this post.

Questions / Comments

×