What Every Java Developer Should Know About Thread, Runnable, and Thread Pool

Multithreading Is Most Complex And Biggest Part Of Java

Multithreading chapters are the most difficult to understand and use in Java. Unfortunately, there are not that many sources where you can get all the answers. Meanwhile, concurrency knowledge is critically important. In this article, I explain the core aspects of multithreading that every Java developer has to know. In this part, we start with the Thread and Runnable subject.

Why Is Concurrency Knowledge So Critical?

You Can’t Get Senior Java Job Without Good Knowledge Of Multithreading

Multithreading knowledge almost certainly is the subject of interviews for senior Java positions. Without a clear understanding of multithreading with and without hands-on experience, you most likely will fail.

Benefits of Senior Java Jobs

Almost Every Production Application Uses Multithreading Paradigm

In practice in real projects, you will use application servers or their alternatives. All of them are based on multithreading solutions like thread pools, etc. Any proper implementation on top of it requires concurrency consistency.

Production Applications Graphic: Apache Tomcat, Spring, and WildFly

Thread and Runnable Definitions

Multithreading is based on Thread and Runnable. Thread is a class that starts new independent activity and performs instructions supplied by Runnable.

Thread vs.  Runnable Graphic

Thread is an entity that is attached to the OS so this is why it’s a heavy class. Meanwhile Runnable is just a set of instructions — so this is why it’s lightweight.

Thread vs.  Runnable Weight Comparison

How to Execute New Thread

Thread can execute instructions inside the current running thread by using Run() method. In order to run instructions in a new activity, Thread provides Start() method.

(new Thread()).run(); // run in current thread
(new Thread()).start(); // run in new thread

Flow Example: Executing New Thread

How to Reuse Thread

Thread can perform many runnables inside of it. Here is an article with more details. Here you can see a very short example with many runnables (tasks) run inside one single thread:

List<Runnable> tasks = new ArrayList<Runnable>();
(new Thread(() -> {
  for (Runnable task : tasks) {
    task.run();
  }
})).start();

Multiple Runnables Running a Single Thread

How to Stop Thread

You can’t just stop() or suspend() thread. These methods are deprecated. You have to take care about interruption design using isAlive() or isInterrupted()

(new Thread(() -> {
    while(true){
      // process a peace of logic
      if(Thread.currentThread().isInterrupted()){
        //handle exiting
        break;
      }
    }
})).start();

Do's and Don'ts of Thread Stopping

Thread Daemon

Thread can be a daemon. Daemon threads are interrupted instantly even the final part won’t be executed. So such threads can be attached to resources. Otherwise, they can be the reason for resource or/and memory leaks.

Thread thread = (new Thread(() -> {
    try {
      // working with resource
    } finally {
      // resource.close(); - might won't work because finally if
      // deamon been interrupted
    }
}));
thread.setDaemon(true);
thread.start();

Daemon Threads

How To Use Thread Pool

As long as the Thread instance is heavy it makes sense to reuse the same Thread using ThreadPool class. You can use different ThreadPool implementations depending on your thread.

Fixed Thread Pool

FixedThreadPool is a simple pool with a predefined number of threads. The number of threads won’t be changed during. It makes sense to use it:

Fixed Thread Pool Over Time

Cached Thread Pool

Opposite to Fixed Thread Pool, this one can increase the number of threads dynamically when more tasks are added. Each newly created thread will be alive while it’s used otherwise it will be removed after 60 seconds of idle.

Cached Thread Pool Over Time

How To Define Number Of Threads In Thread Pool

In order to use the best Thread Pool for your application you need to understand the next things:

  • If your thread does a lot of computation like video rendering, encryption, etc., then it eats processes that run that thread.
  • If your thread runs not related to CPU activity like networking calls, memory calls, etc., then it won’t consume the CPU that runs its thread.

High Computation vs.  Low Computation Activities

Relying on this knowledge you might make the next conclusions:

  • Having high CPU consumable tasks don’t allocate more threads than CPU cores

High CPU Consumable Tasks vs.  CPU Cores

  • Having low CPU consumable tasks you can have a number of threads more than CPU cores (but proportion depends on the specific situation).

Low CPU Consumable Tasks vs.  CPU Cores

Conclusion

This article highlights just the main thing about Thread, Runnable, and Thread Pool notes but doesn’t cover it completely. There are still many aspects that might play an important role. I hope you liked the infographics I used. Please leave your feedback if you think that I missed something critically important related to this subject. Thanks for reading!

.

Leave a Comment