This Tutorial Explains all about Multithreading In Java, Concurrency Implementation, the Life cycle of a thread, Thread Class Example, Thread using Runnable Interface:
The concurrency in the computer world is the ability of a system (be it application, computer, or programming language) to execute several instances of a program or application in parallel.
By running instances or programs concurrently we ensure high throughput and higher performance as we can utilize the untapped resources like operating system hardware etc. For example, if a system has several CPUs, then the application can utilize these CPUs effectively and increase the throughput.
=> Visit Here For The Exclusive Java Training Tutorial Series.
Table of Contents:
What Is Multithreading In Java
In Java, threads can be viewed as the backbone of concurrency. A thread is an executable, lightweight unit that accesses shared resources as well as its own call stack.
A Java application is one process and within this application, we can have multiple threads to achieve concurrency.
We know that an application running on the system can have multiple instances and these are usually called multi-doc applications. These application instances are called processes. Each of these processes is assigned an execution unit known as a thread.
Depending on the operating system and application requirements, the process can be assigned either a single thread or multiple threads. When the application process is assigned multiple threads, then we need to execute these multiple threads simultaneously.
“This technique of executing or running the multiple threads simultaneously or concurrently is known as multithreading.”
Multithreading simply means that -we have more than one thread executing inside the same application.
Java programming language has built-in support for multithreading.
Multithreading is depicted in the above diagram. As shown, there are multiple threads that are running concurrently inside an application.
For example, a desktop application providing functionality like editing, printing, etc. is a multithreaded application. In this application, as printing is a background process, we can perform editing documents and printing documents concurrently by assigning these functions to two different threads.
The threads in multithreaded applications run parallel to each other in a concurrent manner. Thus multithreading is also a part of concurrency in Java. Note that though there are multiple threads, they share the memory area thereby saving on memory. Also, threads can easily switch contexts in no time.
Multithreading is mainly useful as it provides concurrent execution of two or more parts of an application. This lets the application utilize the CPU time to its maximum and idle time is kept to a minimum.
The following are some of the terms that we should know in relation to the multithreading environment as they are used frequently.
Multitasking: In multitasking, more than one task is executed at the same time.
Multithreading: Multithreading, as already mentioned is a process of executing multiple threads simultaneously.
Multiprocessing: In multiprocessing, more than one process is executed simultaneously. Similar to multitasking, but here more than one CPU is involved.
Parallel Processing: Parallel processing is a technique where multiple CPUs work simultaneously in a computer system.
Having discussed multithreading, the question arises as to why we at all need multithreading?
Benefits Of Multithreading
Multithreading has various benefits that aid in efficient programming.
The below points will make it clear.
#1) Efficient Utilization of Single CPU Systems
When there is only one CPU in the system, with a single thread then the CPU time is wasted. When the thread is busy using other resources like IO, the CPU is idle. We can improve on this and better utilize the CPU by having multithreaded applications.
By using multithreading, if one thread is done with CPU, then the other thread can utilize it. With multiple threads, CPU idle time will be greatly reduced.
#2) Efficient Utilization of Multiple CPU Systems
Just like single CPUs, even with systems having multiple CPUs, the multithreaded applications are able to utilize multiple CPUs efficiently.
#3) Improved user experience with respect to Responsiveness and Fairness
The responsiveness of the system improves with multithreaded applications. We do not experience the ‘GUI hanging’ when we have multiple threads accomplishing various tasks in the application and the users do not need to wait for a long time to get a response for their requests.
Similarly, the users are properly services in multithreaded systems.
How To Implement Concurrency In Java
The first class using which we can implement concurrency in Java is java.lang.Thread class. This Thread class forms the basis of concurrency in Java.
We also have java.lang.Runnable interface that can be implemented by a Java class to abstract the thread behavior. For advanced application development, we can make use of the java.util.concurrent package available since Java 1.5.
Moving forward we will discuss concurrency in Java in detail. Let’s discuss and understand the concept of threads in Java in this tutorial. In our subsequent tutorials on multithreading, we will explore various multithreading and concurrency concepts.
What Is A Thread In Java
A single thread can be defined as the smallest and lightweight unit of processing. In Java, threads are used in programs using ‘Thread’ class.
Java threads are of two types:
#1) User thread: user thread is created when the application first starts. Then we can create as many user and daemon thread.
#2) Daemon thread: daemon threads are mainly used in the background and are used for tasks like cleaning the application, etc.
Threads reduce the maintenance cost of the application. It also reduces the application overhead.
A single thread example is shown below:
public class Main{ public static void main (String [] args){ System.out.println("This is a thread"); } }
The above program will display “This is a thread” as when the application starts a user thread is created. In the above program, the main function is the starting point of application and it creates a user thread.
The Life Cycle Of A Thread
The following diagram depicts the life cycle of a thread in Java.
As shown in the above diagram, a thread in Java has the following states:
#1) New: Initially, the thread just created from thread class has a ‘new’ state. It is yet to be started. This thread is also called ‘born thread’.
#2) Runnable: In this state, the instance of a thread is invoked using the method ‘start’.
#3) Running: The thread instance’s start method is invoked and the thread begins execution. This is the running state. Mostly scheduler schedules and manages the threads.
#4) Blocked: There are multiple threads in an application. These threads have to wait for another as their execution has to be synchronized.
#5) Terminated: Once the execution process of the thread is over, the thread is terminated or its execution is stopped.
So a thread is first created, then scheduled and later the scheduler executes the thread. While the running thread may be blocked or suspended for some other activity. Then it is resumed and while processing completes, the thread is executed.
Thread Priorities
A thread priority decides how one thread is to be treated with respect to the other threads in an application. A thread priority is an integer number.
Enlisted below are some points to be remembered about thread priorities:
- Thread priorities are integer numbers.
- Using thread priority, we can decide when we should switch from one thread in running state to another. This is the context switching process wherein we switch contexts of the threads.
- Anytime a thread can voluntarily release its control over CPU. Then the thread with the highest priority can take over.
- Similarly, a higher priority thread can preempt any other thread with lower priority.
- Thread class provides a setPriority () method that is used to set the priority for the thread.
- We can also use constants MIN_PRIORITY, MAX_PRIORITY, or NORM_PRIORITY in the place of integers.
Create A Thread
We can create a thread using either of the following ways:
- Extending the Java ‘Thread’ class.
- Implementing ‘Runnable’.
Extending The Java ‘Thread’ Class
The class ‘Thread’ contains the constructors and methods that allow us to create and perform operations on a thread object. Internally the Thread class implements Runnable interface and also extends Object class.
The following table gives a summary of various constructors and methods of a Thread () class.
Constructor/ | Prototype | Description |
---|---|---|
Thread () constructor | Thread() | Default constructor to create a Thread object. |
Thread(String name) | Constructor to create a Thread object with specified name. | |
Thread(Runnable r) | Create a Thread instance with specified Runnable interface object. | |
Thread(Runnable r,String name) | Create a Thread instance with specified Runnable interface object and given name | |
run | public void run() | Run method performs the action for a thread. Invokes the thread. |
start | public void start() | Used to start the execution of the thread. Internally the JVM calls run () method on this thread. |
sleep | public void sleep(long milliseconds) | The execution of the current thread is stopped for specified milliseconds. |
join | public void join() | Wait for the thread to die |
public void join(long milliseconds) | Wait for specified milliseconds for the thread to die. | |
getPriority | public int getPriority() | Return the thread priority |
setPriority | public int setPriority(int priority) | Change the thread priority to specified priority |
getName | public String getName() | return the name of the thread. |
setName | public void setName(String name) | Set the name of the thread to specified string |
currentThread | public Thread currentThread() | Returns the reference of the thread that is currently active |
getId | public int getId() | Return thread Id |
getState() | public Thread.State getState() | Returns current state of the thread |
isAlive | public boolean isAlive() | Check if the thread is alive and return true if yes. |
yield | public void yield() | Temporarily pauses the current thread and allows other threads to execute. |
isDaemon | public boolean isDaemon() | Check if the thread is a daemon thread; return true if yes. |
setDaemon | public void setDaemon(boolean b) | Set the thread as a daemon thread if b=true; else set as user thread. |
interrupt | public void interrupt() | Interrupt the current thread. |
isInterrupted | public boolean isInterrupted() | Check if thread is interrupted. |
interrupted | public static boolean interrupted() | Check if current thread has been interrupted. |
dumpStack | Static void dumpStack() | Prints a stack trace of the current thread to the standard error stream. |
suspend | public void suspend() | Suspends all threads. (** method is deprecated in latest Java versions) |
resume | public void resume() | Resume suspended thread. (** method is deprecated in latest Java versions) |
stop | public void stop() | Stops the thread. (** method is deprecated in latest Java versions) |
We will elaborate on these thread methods in our next tutorial on multithreading.
Starting a thread
The method start () that is used to start the thread performs the following steps:
- Starts a new thread instance with a new CallStack.
- The thread state is changed from new to runnable.
- When it is the turn of the thread, it executes the run () method.
Implementing The ‘Runnable’ Interface
A thread instance can also be created using the Runnable interface. To create a thread instance, the class whose objects should be executed by a thread should implement the Runnable interface.
The Runnable interface has only one method:
public void run () => this method is used to execute the thread.
Thread Class Example
Now let’s demonstrate thread in Java using thread class.
//class inherited from "Thread" class ThreadClassDemo extends Thread { private int number; //class constructor public ThreadClassDemo(int number) { this.number = number; } //run method => execution code for thread public void run() { int counter = 0; int numInt = 0; //prints the number till specified number is reached, starting from 10 do { numInt = (int) (counter + 10); System.out.println(this.getName() + " prints " + numInt); counter++; } while(numInt != number); System.out.println("** Correct! " + this.getName() + "printed " + counter + " times.**"); } } public class Main { public static void main(String [] args) { System.out.println("Starting thread_1..."); //create a thread class instance Thread thread_1 = new ThreadClassDemo(15); //start the thread thread_1 thread_1.start(); try { //wait for thread_1 to die thread_1.join(); } catch (InterruptedException e) { System.out.println("Thread interrupted."); } System.out.println("Starting thread_2..."); Thread thread_2 = new ThreadClassDemo(20); //start thread_2 thread_2.start(); System.out.println("main() is ending..."); } }
Output
Java Thread Using Runnable Interface
The following example demonstrates the use of the Runnable interface to create a thread instance.
//class implements Runnable interface class RunnableDemo implements Runnable { private String message; //class constructor public RunnableDemo(String message) { this.message = message; } //run method public void run() { while(true) { System.out.println(message); } } } public class Main { public static void main(String [] args) { //create first thread instance hello Runnable hello = new RunnableDemo("Hello, Greetings!!!"); Thread thread1 = new Thread(hello); thread1.setDaemon(true); //set this thread as daemon thread1.setName("hello"); System.out.println("Starting First thread..."); //start the thread thread1.start(); //create second thread instance bye Runnable bye = new RunnableDemo("Bye for now!!"); Thread thread2 = new Thread(bye); thread2.setPriority(Thread.MIN_PRIORITY); //set priority to min thread2.setDaemon(true); //set as daemon thread System.out.println("Starting goodbye thread..."); //start the thread thread2.start(); System.out.println("main() is ending..."); } }
Output
How To Stop A Thread In Java
We have seen the thread examples above. From these examples, we know that when the run method finishes execution, the thread stops or it also stops because of some exceptions.
Earlier versions of Java had a stop () method in Thread class that could be used to directly stop the thread. But it has now been deprecated for safety reasons. Thus we need to employ the other methods in order to stop the thread that is executing.
There are two methods we can employ to stop the thread.
- Using a Volatile boolean variable
- Using Interrupts.
In this section, we will discuss both these methods of stopping a thread.
Using A Volatile Boolean Variable
In this method, we maintain a boolean variable say flag, to stop the thread. The thread runs as long as the boolean variable is set to true. The moment it becomes false, the thread is stopped.
The specialty of this method is that we declare the boolean variable as “volatile” so that it is always read from the main memory and the program cannot cache it in the CPU cache. This way, there will not be any difference in the values set and read.
The implementation of stopping a thread using a volatile boolean variable is shown below.
class StopThread extends Thread { private volatile boolean stop_flag = true; //initially set to true public void stopRunning() { stop_flag = false; //set stop_flag to false } @Override public void run() { while (stop_flag) { //keep checking value of stop_flag System.out.println("Thread is running..."); } System.out.println("Thread stopped!!!"); } } public class Main { public static void main(String[] args) { //create a thread instance StopThread stop_thread = new StopThread(); //start the thread stop_thread.start(); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } //call stopRunning() method to stop the thread stop_thread.stopRunning(); } }
Output
Note: Here we have shown only a part of the output. The thread might run for several minutes before stopping. So that we can obtain different output on different systems.
Using Interrupts
Here the thread is stopped using the interrupt () method as we already discussed above in the thread class methods. The interrupt () method sets the status of the thread as interrupted. This status is passed to the while loop of the run () method. We can obtain the interrupted status using the interrupted () method.
The following program demonstrates the usage of interrupt () method to stop the thread.
class StopThread extends Thread { @Override public void run() { while (!Thread.interrupted()) { //check for interrupted status System.out.println("Thread is running..."); } System.out.println("Thread stopped!!!"); } } public class Main { public static void main(String[] args) { //create a thread instance StopThread stop_thread = new StopThread(); //start the thread stop_thread.start(); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } //interrupt the thread stop_thread.interrupt(); } }
Output
Frequently Asked Questions
Q #1) Why do we use Multithreading in Java?
Answer: Multithreading allows concurrent or simultaneous execution of two or more threads in an application. The concurrent execution maximizes the Throughput and also utilizes the CPU to its maximum.
Q #2) What is Multithreading? What are its types?
Answer: Multithreading means executing more than one thread. This execution can be concurrent or parallel. Thus, multithreading has two types i.e. concurrent or parallel.
Q #3) What is Multithreading vs. Multiprocessing?
Answer: In multithreading, there are multiple threads for the same or different processes and these threads execute concurrently to enhance the computing speed of a system. In multiprocessing, a system has more than two CPUs and multiple processes execute simultaneously.
Q #4) What are the advantages of Multithreading in Java?
Answer: Using multithreading we can execute different parts of an application simultaneously using threads. Multithreading increases system throughput. Multithreading also maximizes CPU utilization as different threads continuously use the CPU.
Q #5) Is Multithreading good for gaming?
Answer: Yes, especially for modern games.
Conclusion
This is all about the introduction of multithreading. We have discussed the concurrency and multi-threading in Java in this tutorial. We discussed the creation of a thread with Thread class as well as the Runnable interface and have provided appropriate examples.
We have also learned the concepts of a single thread and its creation in detail. The thread concepts including the life cycle of a thread, stopping a thread, types of thread, etc. have been discussed in this tutorial.
We also discussed multithreading at length and concurrency in Java. At the end of this tutorial, the reader should be able to easily grasp the concepts of concurrency and multithreading and also threads in Java.
=> Watch Out The Simple Java Training Series Here.