Java | Multithreading

Prayukti Jain
The Startup
Published in
8 min readAug 10, 2020

--

Concurrent execution of multiple programs at a time (running Word and Chrome simultaneously) is Multiprogramming. Likewise, execution of multiple tasks ( processes, programs, threads etc.) at a time is Multitasking. The major difference between them is, multi-programming works solely on the concept of context switching, whereas multi-tasking is based on time sharing.

Multithreading is a process of concurrent execution of two or more parts of a program, for maximum utilization of CPU. Also, Multithreading is an extension of multitasking, where you can sub-divide specific operations within a single application, into individual threads. Each of these threads can run in parallel. The Operating System divides processing time, not only among different applications, but also among each thread within an application. It enables you to write a program in a way where multiple activities can proceed concurrently.

What is Thread?

A thread is basically a light-weight process and Java provides built-in support for a multithreaded programming. A Multithreaded Program is one, that contains two or more parts that can run concurrently. Each part of such program is called Thread. Every thread defines a separate path of execution.

The Main() method in Java is also executed on a special thread, which is created by the Java Virtual Machine to run your application. From inside your application, you can create and start more threads, which can execute parts of your application utilities in parallel with the main thread. Yet another point to remember is, Threads running in parallel does not actually means they are running at the same instance. The control of accessing the processor is switched between threads. These threads although runs on a single processor and share common resources.

Life cycle of a Thread:

A thread goes through numerous stages like, a thread is born, starts, runs and then eventually dies. Life cycle of thread:

New: A thread begins its life cycle at this stage. The thread remains in the new state until the program starts it.

Runnable: As the program starts the new thread, the thread becomes runnable. Thread at this stage is considered to be executing its part of application, when the processor is available.

Running: When the processor gives time to thread, for execution, the thread is said to be in Running state.

Waiting: When the thread waits for another thread to perform a task, the thread is said to be in waiting state. This is goes back to the running state , as soon as it receive signal from the running thread to continue execution.

Blocked: When thread is prevented from entering the running state or runnable state, due to its suspension or sleep, the thread is considered to be in blocked state.

Dead: The thread enters this state when it completes the execution of task. The thread is terminated at this state.

Creating a Thread:

Threads can be creating using 2 mechanisms:

  1. Implementing the Runnable Interface.
  2. Extending the Thread class.

Implementing the Runnable Interface:

For this mechanism, we need to create a class that implements Runnable interface. Since, the class will be implementing the Runnable interface, we need to define all the methods, declared in the interface. Luckily, Runnable interface got only one method declared in it, that is, run() method. So we need to define the run method in our class.

Once we are done with this, we only need to instantiate our class, create an object of Thread and pass the reference of the object of our class for the constructor of the Thread class, and call the start() method of the thread class. Start method will then load the run() method of the class whose reference was received through the constructor. And hence, run method of our class will be executed on a separate thread.

class MyThread implements Runnable{public void run(){try{
// Displaying the running thread
System.out.println("Thread " + Thread.currentThread().getId() + " is running..");
}catch(Exception exception){
System.out.println(exception.getMessage()); // Exception handling
}
}
}
class Multithreading{public static void main(String args[]){for(int i = 1 ; i <= 5 ; i++) {//Instantiating Thread
Thread thread=new Thread(new MyThread());
// loads the run method of MyThread class
thread.start();
}
}
}

Compile and execute the above code multiple time and you will be witnessing the different output, each time you execute it. The output at my machine looked like this.

Difference in output each time is proof of concept for Multithreading

Extending the Thread class:

For this mechanism, we need to create a class that extends java.lang.Thread class. The Thread class implements the Runnable interface and hence, would have defined the run method in it. So this time, we just need to override the run method in our class.

Once we have designed the class with run method, we will instantiate it and call the start() method. Since we haven’t written a start method, according to Java rules, start method of Thread class will be executed, which will stack up the run method of our class and eventually the part of application in the run method will be executed.

class MyThread extends Thread{public void run(){try{
// Displaying the running thread
System.out.println("Thread " + Thread.currentThread().getId() + " is running..");
}catch(Exception exception){
System.out.println(exception.getMessage()); // Exception handling
}
}
}
class Multithreading{public static void main(String args[]){for(int i = 1 ; i <= 5 ; i++) {//Instantiating Thread
MyThread myThread=new MyThread();
// load the run method of MyThread class
myThread.start();
}
}
}

Compile and execute this as done previously and you will be again witnessing the randomized output every time you execute it. And this is the proof of concept of Multithreading.

Some useful Thread methods:

We can use number of thread methods for performing our action, but some favourable methods are described below. These methods are static method, and invoking this performs the action on the currently running thread.

  1. public static void getAllStackTraces(): returns a map containing Thread mapped to an array that represents the stack trace of the corresponding thread.
  2. public static boolean holdsLock(Object): returns true if and only if, the current thread holds the monitor lock on the specified object.
  3. public static Thread currentThread(): returns the reference to the currently executing thread.
  4. public static int activeCount(): returns an estimate of the number of active threads in the current thread group.
  5. public static void sleep(millis): causes the currently executing thread to temporarily cease execution, for the specified number of milliseconds.

Some more useful non-static methods are :

  1. public long getId(): returns the identifier of this Thread.
  2. public void start(): causes this thread to begin execution by stacking up the run method of the corresponding class.
  3. public final void join(): waits for this thread to terminate.
  4. public void run(): if thread is instantiated using either by extending the Thread class, or by implementing the runnable interface, then this method is called. If defined, it contains a part of the application code.
  5. public final void setPriority(int): sets the priority of this Thread. Priority can vary from 1 to 10, where 1 being the highest priority and 10 being the least priority.

Thread Priority:

Each thread has a priority. Thread scheduler assigns processor to each thread based on this priority. Priority can either be given by JVM or it can be given by programmer explicitly. The priority can range from 1 to 10. There are 3 more static variables defined in Thread class for priority.

public static int MAX_PRIORITY: The maximum priority that a thread can have.public static int MIN_PRIORITY: The minimum priority that a thread can have.public static int NORM_PRIORITY: The default priority that is assigned to a thread.

Useful methods for priority:

  1. public final int getPriority(): Returns this thread’s priority.
  2. public final void setPriority(int priority): Changes the priority of this thread. This method throws IllegalArgumentException if value of priority goes beyond minimum(1) and maximum(10) limit.

Below is the code and its output will help in better understanding of the same:

import java.lang.*; 
class MyThread extends Thread {
public void run() {
System.out.println("Run method invoked..");
}
}
class Multithreading {
public static void main(String args[]) {
MyThread thread1= new MyThread();
MyThread thread2 = new MyThread();
MyThread thread3 = new MyThread();
//Default priority is 5
System.out.println("Priority of thread1 : "+ thread1.getPriority());
System.out.println("Priority of thread2 : "+ thread2.getPriority());
System.out.println("Priority of thread3 : "+ thread3.getPriority());
//Setting priority
thread1.setPriority(2);
thread2.setPriority(5);
thread3.setPriority(8);
// thread3.setPriority(11);
//will throw IllegalArgumentException
System.out.println("Priority of thread1 : "+ thread1.getPriority());
System.out.println("Priority of thread2 : "+ thread2.getPriority());
System.out.println("Priority of thread3 : "+ thread3.getPriority());
System.out.println("Priority of Main thread : " + Thread.currentThread().getPriority());
}
}

Compile and execute the above code as done previously and your output must look like:

Thread Priority

Thread Exceptions:

When an exception occurs, the normal flow of the program gets disrupted and the program terminates abnormally, which is not recommended, therefore, these exceptions needs to be handled. Some of the commonly used exceptions, are:

Sleep() method gives rise to:

IllegalArgumentException - If the value of millis is negative or beyond the limitsInterruptedException - If any thread has interrupted the current thread, The interrupted status of the current thread is cleared when this exception is thrown.

start() method gives rise to:

IllegalThreadStateException - If the thread was already started.

Some other exceptions can be namely:

  1. SecurityException
  2. NullPointerException
  3. NoSuchMethodError

Thread Safety:

In Multithreading, several threads are executed simultaneously, so odds may be that they might access the same resource. This act can lead to sharing of resources by multiple threads at the same time, leading to inconsistent change in the data. This can create enormous problem when implemented in any project. So, this chaos is solved by using a Thread-safety process. In this process, a thread, working on an object, prevents other threads from working on the same object, hence providing a Thread-safe code.

Synchronization:

Synchronization is a way of achieving Thread safety. It allows only one thread to complete the particular task. It can be implemented using a synchronized keyword, which is a modifier that creates a block of code known as a critical section. Below is the code for implementing it:

class Sync {

synchronized void sum(int n) {
// Creating a thread instance
Thread thread = Thread.currentThread();
for (int i = 1; i <= 5; i++) System.out.println("Processing "+thread.getName() + " : " + (n + i));
}
}
class MyThread extends Thread { // Creating an object of class Sync for accessing resource
Sync sync=new Sync();
public void run() {
sync.sum(10);
}
}
class Multithreading {public static void main(String args[]) {//Instantiating MyThread class
MyThread myThread=new MyThread();
//Instantiating thread instances
Thread thread1 = new Thread(myThread);
Thread thread2 = new Thread(myThread);
thread1.setName("Thread A");
thread2.setName("Thread B");
// Starting thread instance thread1 and thread2
thread1.start();
thread2.start();
}
}

Compile and execute without and with synchronize keyword and your output will look like this, respectively:

Without and With synchronize keyword

Conclusion:

In this article, we learned what are threads, what is Multithreading, ways of creating threads, some utilities from Thread class, its priority, exceptions, and safety. Do look out for other articles to get knowledge about various topics, and feel free to drop a comment for doubts or suggestions.

What are the top 10 useful functions of Underscore.js?

What are Decorators in Python?

Multithreading in Java

Understanding Apache Derby using Java

TCP/IP Socket Programming in Java

How to send HTTP Requests using React JSX?

--

--

Prayukti Jain
The Startup

Software Engineer at Microsoft | ex - Walmart | Content Writer | Open to Learn and Help