Multi-Threading in Java

Kaustubh Trivedi
MDG Space
6 min readFeb 22, 2020

--

Thread: Lightweight subprocess, with a separate and independent path of execution, created by java.lang.Thread class.
Note: Instructions in a single thread always run synchronously.

States of a Thread

Taken from GFG
  • NEW: Thread created but not yet started.
  • RUNNABLE: Thread ready to run is moved in runnable state. Here, a thread is either running or is ready to run in JVM, though it may be waiting for other resources from the operating system such as processor.
  • BLOCKED: Thread temporarily inactive as it tries to access a protected section of code that is currently locked by some other thread.
  • WAITING: Thread temporarily inactive as its waiting for another thread to perform a particular action. Caused by calling:
    1. Object.wait with no timeout
    2. Thread.join with no timeout
    3. LockSupport.park
  • TIMED_WAITING: Thread waiting for a specified time. Caused by:
    1. Thread.sleep
    2. Object.wait with timeout
    3. Thread.join with timeout
    4. LockSupport.parkNanos
    5. LockSupport.parkUntil
  • TERMINATED: A thread that has exited is in this state.

Creating Threads

All threads are created cascading from the main thread. Threads are created as:

  • If the main thread has some long-running task, then as a thread is synchronous, this task will make the application appear non-responding. So, long-running independent tasks (like downloading files) must be run on separate threads.
  • Multithreading allows concurrency and can increase performance by using multiple CPU cores.

Method 1: Using Thread Class

  • How to use?
    1. Create class MyThread, and extend class Thread.
    2. Override method run().
    3. Create object of MyThread class and invoke method start() which starts running code present in method run() in a new thread.
  • Difference between start() and run():
    1. start() creates a new thread and runs the code in run() in that, but if you call run() directly, the code in it will be executed in the same thread.
    2. You can call start() on an thread instance once only (as it changes the state of thread), though run() can be called any number of times.

NOTE: Understand that CPU can switch between threads at any instance. Run this code multiple times and observe.

Method 2: Using Runnable Interface:

This is required and preferred as multiple-inheritance is not allowed in java.

Note: Anyhow, you need to use Thread class only to create and execute a new thread. Constructors of class Thread can have either, none or all of the following parameters:

  • runnable_object
  • thread_name (String)

Runnable reduces lines-of-code:

  • Use anonymous class while passing object of Runnable in Thread constructor.
  • Use lambdas, as Runnable is a functional interface.

How to use?

  1. Create class MyRunnable, implement interface Runnable.
  2. override method run()
  3. Create object of Thread by passing instance of MyRunnable.
    Thread thread = new Thread(myRunnable);
  4. Execute thread by thread.start()

Examples for Syntax

Thread using class Thread

Take note of line 9, 30.

Thread using interface Runnable

  • Without using anonymous class and lambdas:
  • Using anonymous class and lambdas:

Daemon Threads

Daemon thread is the lowest priority thread that runs in the background to perform tasks such as garbage collection. Daemon threads cannot prevent JVM to exit once all users have completed execution (which means once all user threads are executed, JVM exits, closing all daemons threads also, even if they are running)
Syntax:

Because of line 10, nothing will print (as main exits as soon as t starts). Check this out.

Some Important Methods

Thread.currentThread() :

This static method return object of currently executing thread. Helpful in static context and where current class does not extend Thread.

NAME and ID related methods:

Note: You can never set id for any thread.

  • Using constructor: In the constructor of the class Thread, one may pass thread name as parameter. If you use MyThread extends Thread use super. See [ThreadUsingThreadClass] example.
  • Using getters and setters:
    - Can use thread.getName(), thread.getId() to get the respective.
    - Can use this as thread object inside a Thread class.
    - You may get the thread object using Thread.currentThread(). Helpful to get thread object in static functions.
    - Can use thread.setName("<name>") for changing/setting name of a thread.

Thread.sleep(millisecs):

This method is used to make the current thread sleep for some milliseconds.

thread.isAlive() & thread.join()

A thread is alive if it has been started and has not yet died.

A thread “starts” when its start() method is invoked and “dies” at the end of its run() method. So yes, a thread is “alive” when its run() method is still ongoing, but it is also “alive” in the time window between the invocation of start() and the implicit invocation of the run() method by the JVM.

Usage:

Output:

false
true
true
false

Output if you comment m.join():

false
true
true
true

Thread Priorities

In JVM every thread must have a priority either given by default by JVM or by the programmer. Thread priorities in java vary from 1 to 10 (priority increases with the number).

  • 1 = least priority
  • 5 = normal priority
  • 10 = highest priority

Default Priority: Child thread has the same priority as parent thread by default. The main thread has priority 5 by default.

Meaning of priority: Thread with the highest priority will get execution chance prior to other threads. If two have the same priority then we can’t expect which thread will execute first (depends on scheduler’s algo).

Inbuilt constants: Thread.MIN_PRRIORITY, Thread.MAX_PRIORITY, Thread.NORM_PRIORITY.

Methods: thread.setPriority(int p), thread.getPriority().

Synchronized Keyword

In multithreading, multiple threads may try to access the same resources and finally produce erroneous results.

Synchronized Blocks (marked by keyword synchronized): Help in synchronization of tasks of different threads. A synchronized block in Java is synchronized on some object. All synchronized blocks synchronized on the same object can only have one thread executing inside them at a time.

In Java, synchronization is implemented using a concept called monitors. Only one thread can own a monitor at a given time.

Try to run the following code multiple times, you will find different results every time (as line 5 is not a single instruction and thread may change in between).

Solution: Add keyword synchronized to method increament().

Inter-Thread Communication

Communication between two threads is done basically using methods: wait(), notify(), notifyAll() methods.

Inter-thread communication is required when there is a dependence between two threads to perform a task which arises basically due to order in which parts of the task are to be done. This can be done using Polling (checking condition repeatedly).

A better approach can be to:

  • Make the methods of the object which will make a thread wait or notify as synchronized.
  • If a thread A is dependent on some update from B, then:
    - Make them work on the same object
    - Make thread A wait().
    - Make change from thread B and notify()

NOTE: Methods wait(), notify(), notifyAll() are present in class Object and not in class Thread.

Thread Lifecycle

Difference b/w notify() and notifyAll()

  1. notify() method send notification to only one of waiting thread while notifyAll() informs all threads waiting on that lock.
  2. Using notify(), it’s not guaranteed that, which thread will be informed.
  3. notifyAll() can drain more CPU cycles than notify() itself but if you really want to sure that your notification doesn’t get wasted by any reason, use notifyAll().

Example: Producer-Consumer Problem

Desired: We want that as in a loop a sequence of putting a new value and getting it occurs.

Consider the program:

You will notice patterns like:

Put: 1
Put: 2
Get: 1

So we are getting the wrong value and the methods are not in order. Wrong value issue can be used by using the synchronized keyword for put() and get(). But, then the correct order may still not appear (try making the waiting times for while loops different to make the order problematic).

Correct way:

Here we have updated the put() and get() methods.

Notice:

  1. Multiple threads that are communicating using wait() and notify() must run on the same instance of the class Object.
  2. The wait(), notify(), notify() are all part of class Object so must be present in the functions of the shared object.
    - Note: Such functions must be synchronized.
  3. In the above code, you can even change the sleep time for producer and consumer by any amount (bringing any difference), still, it won’t cause any problem.
  4. Try to notice the difference between sleep and wait.
    - sleep is time-based, but wait makes thread wait for notification.
    - sleep is part of Thread class but wait is part of Object class.

--

--

Kaustubh Trivedi
MDG Space

Code is fun, especially the sound of every key-stroke ;)