Greetings friends! This Java tutorial covers Java multithreading and explains the concept with examples.
Apart from the basics, you will also learn the pros & cons of threading in Java and explore the thread lifecycle. After that, we’ll give an overview of the thread class and its methods.
Finally, you’ll know how to create threads using the Thread class and the Runnable interface. Also, we’ve supplemented the thread concepts with the help of classic examples and code samples. Let’s begin.
Multithreading Programming in Java
Firstly, it’s important to understand the idea of a process and thread in general programming. After that, we can focus on how Java supports these.
What Does a Process Mean in Computer Science?
- A process is a unit of execution in an operating system. Similarly, threads are a much lighter entity inside a process that performs a specific task.
- A thread cannot exist on its own; it must be a part of a process. A process can not end if these entities are not finished execution.
What Does a Thread Mean in Computer Science?
- The thread is a lightweight sub-process and the smallest unit of execution.
- Each thread has a separate path of execution.
- It shares the memory area of the process.
Let’s now get started and explore the world of multithreading.
What is Multithreading in Java?
- Java multithreading enables the execution of multiple threads simultaneously.
- It allows a process to run its tasks in parallel mode on a single processor system.
Now one question you may ask that what made this concept so famous. To get clarity, let’s see some of the benefits of using multithreading.
What are the Pros and Cons of Java Multithreading?
Pros:
- Better use of system resources.
- Parallel execution of tasks and thus less execution time
- Enhanced performance on multi-processor machines
- Improved GUI responsiveness
- Independent threads (don’t impact other threads of the same process if an exception occurs)
Multithreading doesn’t always yield benefits. It comes with its disadvantages too. Let’s go through some of its typical limitations.
Cons:
- It results in the increased complexity of the code.
- Synchronization of shared resources (objects, data) is CPU/memory intensive.
- Debugging is hard because sometimes you can’t predict the results.
- Increased potential for deadlock occurrence.
- “Starvation” some of the threads may not be served with due to poor design.
What is Thread Lifecycle in Java?
Before moving on to creating a thread, we’ll first see the various phases through which the thread has to pass to complete its lifespan.
- New
- Runnable
- Running
- Non-Runnable (blocked)
- Terminated
New- A thread is in the new state when you create the instance of the thread class, but the start() method is yet to get called.
Runnable- The thread is in runnable after executing the start() method. In this stage, it waits for the thread scheduler to run it.
Running- A thread picked by the thread scheduler for execution remains in a running state.
Non-Runnable (blocked)- In this state, the thread remains alive, but it is not eligible to run. It may be due to some sleep operation, waiting for any File I/O to finish or in the locked state, etc.
Terminated- A thread is said to be in the terminated state when its run() method exits.
So far, you’ve read the basic concepts of Java multithreading, let’s now move to learn the different ways to create threads.
How to Implement Multithreading in Java?
In Java, we’ve got the following two ways to create threads.
- Extend the Thread class, or
- Implement the Runnable interface.
It is essential to learn that Java has supplied most of the thread functionality into the Thread class. So, before we jump to the thread creation part, let’s first understand the different features and methods available in the Thread class.
Java accomplishes multithreading through its java.lang.Thread
class. To become efficient in writing the multithreaded code you must know about the constructors and the methods of thread class before starting to write multithreading programs in Java.
List of Thread Class Constructors
Thread class has the following eight constructors.
Thread(): It creates a Thread object with a default name.
Thread(String name): It creates a Thread object with a name that the name argument specifies.
Thread (Runnable target): This method constructs Thread with a parameter of the Runnable object that defines the run() method.
Thread (Runnable target, String name): This method creates Thread with a name and a Runnable object parameter to set the run() method.
Thread(ThreadGroup group, Runnable target): It creates a Thread object with a Runnable object and the group to which it belongs.
Thread (ThreadGroup group, Runnable target, String name): It creates a Thread object with a Runnable object that defines the run() method, specified name as its name, and the Thread object belongs to the ThreadGroup referred to by the group.
Thread(ThreadGroup group, String name): It creates a thread that has the specified name and associates to the ThreadGroup given as the first parameter.
Thread(ThreadGroup group, Runnable target, String name, long stack size): This constructor specifies the ThreadGroup parameter and the size of the thread’s method-call stack.
General Methods to Manage Threads
start():
When the program calls the start() method a new Thread is created, and code inside the run() method gets executed in a new Thread.
run():
This method is the Entry point for the thread.
Let’s see a sample code that shows how to use the start() and run() methods.
package com.techbeamers.multithreading; class MultithreadDemo extends Thread{ public void run(){ System.out.println("My thread is in running state."); } public static void main(String args[]){ MultithreadDemo obj=new MultithreadDemo(); obj.start(); } }
Output: My thread is in running state.
String getName():
You can use this method to get the name of the current thread.
setName(String name):
You can use it to set the name of the thread.
During a debugging session, it’s helpful as we can distinguish between threads. By default, Java also sets the label for each Thread. Alternatively, you can also give a name to the Thread using the Thread constructor that takes the name as an argument. The method setName(String name) can also update the Thread name.
Let’s see a sample code that shows how to give a name to the Thread using the Thread(String name) constructor, setName(String name) method, and retrieve that name in the run() function using getName()
method.
Sample code:
package com.techbeamers.multithreading; class NameMyThread { public static void main (String [] args) { MyThread mt; if (args.length == 0) mt = new MyThread (); else mt = new MyThread (args [0]); mt.start (); } } class MyThread extends Thread { MyThread () { // The compiler creates the byte code equivalent of super (); } MyThread (String name) { setName (name); // Pass name to Thread superclass } public void run () { System.out.println ("My name is: " + getName ()); } }
Sample output.
If you forget to provide any name while running the code, you’ll see the following output.
Java NameMyThread Output: My name is: Thread-0
If you give a name to a thread as “DemoThread,” then the output will be.
Java NameMyThread DemoThread Output: My name is: DemoThread
Sleep (long milliseconds):
It suspends a thread for the specified period. If any other thread interrupts this sleeping thread, it will throw an InterruptedException. So it is suggested to enclose the sleep() method in the try block. Alternatively, the code’s method must include InterruptedException in its throws clause.
boolean isAlive():
It determines if a thread is still running. JVM considers a thread to be alive immediately before calling to thread’s run() method, during the execution of the thread’s run(), and immediately after return from run().
During that interval, the isAlive() method returns a “true” Boolean value. Otherwise, it returns false.
This method is useful in situations when one thread needs to wait for another thread to finish its run() method.
Check out the below sample code:
package com.techbeamers.multithreading; class MyThread extends Thread{ public void run(){ System.out.println("My thread is in running state."); } } class ThreadSleepDemo{ public static void main(String args[]){ MyThread obj=new MyThread(); obj.start(); while(obj.isAlive()) { try { obj.sleep(10); } catch(InterruptedException e) { System.out.println(“Sleeping thread interrupted”); } System.out.println(“Thread-Sleep Demo Complete”); } } }
Output: My thread is in running state Thread-Sleep Demo Complete
join(long milliseconds):
This method gets called when a thread wants to wait for another thread to terminate. Let’s see a sample code for the <join()> method.
Check out the below sample code:
package com.techbeamers.multithreading; class MyThread extends Thread{ public void run(){ System.out.println("My thread is in running state."); } } class ThreadJoinDemo{ public static void main(String args[]){ MyThread obj=new MyThread(); obj.start(); try { obj.join(); } catch(InterruptedException e) { } System.out.println(“Thread-Join Demo Complete”); } } }
Output: My thread is in running state Thread-Join Demo Complete
Set Thread Types.
Threads fall under into following two categories.
- User, and
- daemon.
A user thread performs critical tasks that must be finished before the application terminates. However, a daemon thread performs garbage collection and other background tasks. When an application’s starting thread (a user thread) ends, JVM checks whether any other user thread is running. If there is some running user thread, then JVM prevents the application from terminating. If there is no user thread running, then JVM will end the program without bothering the running daemon thread.
- Boolean isDaemon(): checks if the thread is a daemon thread.
- setDaemon(boolean b): marks the thread as a daemon or user thread. To start a daemon thread setDaemon(Boolean b) method must be called with an argument “true.”
Check out the below sample code:
package com.techbeamers.multithreading; class DaemonThreadDemo { public static void main (String [] args) { MyThread mt = new MyThread (); mt.setDaemon (true); mt.start (); try { Thread.sleep (100); } catch (InterruptedException e) { } } } class MyThread extends Thread { public void run () { System.out.println ("Daemon is " + isDaemon ()); } }
Output: Daemon is true
Thread currentThread():
It returns the instance reference of the currently executing thread.
Thread.State getState():
It returns the state of the thread.
Check out the below sample code:
package com.techbeamers.multithreading; class ThreadStateTest { public static void main (String [] args) { Thread currentThread = Thread.currentThread(); System.out.println(currentThread); MyThread mt1 = new MyThread (); mt1.setName("MyThread1"); MyThread mt2 = new MyThread(); mt1.setName("MyThread2"); System.out.println("Thread State of MyThread1 before calling start: "+mt1.getState()); mt1.start (); mt2.start(); System.out.println("Thread State of MyThread1 in Main method before Sleep: " + mt1.getState()); System.out.println("Thread State of MyThread2 in Main method before Sleep: " + mt2.getState()); try { Thread.sleep (1000); } catch (InterruptedException e) { } System.out.println("Thread State of MyThread1 in Main method after Sleep: " + mt1.getState()); System.out.println("Thread State of MyThread2 in Main method after Sleep: " + mt2.getState()); } } class MyThread extends Thread { public void run () { System.out.println ("Run by " + Thread.currentThread().getName()); try { Thread.sleep (100); } catch (InterruptedException e) { } System.out.println("Thread State of: "+ Thread.currentThread().getName()+ " - "+Thread.currentThread().getState()); System.out.println("Exit of Thread: " + Thread.currentThread().getName()); } }
Sample output:
Output: Thread[main,5,main] Thread State of MyThread1 before calling start: NEW Run by MyThread2 Thread State of MyThread1 in Main method before Sleep: RUNNABLE Run by Thread-1 Thread State of MyThread2 in Main method before Sleep: RUNNABLE Thread State of: MyThread2 - RUNNABLE Exit of Thread: MyThread2 Thread State of: Thread-1 - RUNNABLE Exit of Thread: Thread-1 Thread State of MyThread1 in Main method after Sleep: TERMINATED Thread State of MyThread2 in Main method after Sleep: TERMINATED
yield():
This method causes the currently executing thread object to pause temporarily and allow other threads to run.
Check out the below sample code:
package com.techbeamers.multithreading; public class ThreadTest extends Thread { public void run() { System.out.println("In run"); yield(); System.out.println("Leaving run"); } public static void main(String []argv) { (new ThreadTest()).start(); } }
The thread will halt after printing “In Run” due to the yield() method. Since there is no other thread to execute, it will resume and print “Leaving run.”
Output: In Run Leaving Run
final int getPriority()
:
It returns the priority of the thread.
final void setPriority(int priority):
This function is used to change the priority of a thread.
Check out the below sample code:
package com.techbeamers.multithreading; public class ThreadDemo { public static void main(String[] args) { Thread t = Thread.currentThread(); t.setName("Admin Thread"); // set thread priority to 1 t.setPriority(1); // prints the current thread System.out.println("Thread = " + t); int priority= t.getPriority(); System.out.println("Thread priority= " + priority); int count = Thread.activeCount(); System.out.println("currently active threads = " + count); } }
Output: Thread = Thread[Admin Thread,1,main] Thread priority= 1 currently active threads = 1
int getId():
It returns the id of the thread.
interrupt():
It interrupts the thread.
boolean isInterrupted()
:
tests if the thread has been interrupted and returns the interrupted flag either true or false.
boolean interrupted():
The static interrupted() method tests if the thread has been interrupted. This method returns the interrupted flag after that it sets the flag to false if it is true.
Check out the below sample code:
package com.techbeamers.multithreading; public class TestThreadInterrupt extends Thread { public void run() { for (int i = 1; i <= 2; i++) { if (Thread.interrupted()) { System.out.println("code for interrupted thread"); } else { System.out.println("code for normal thread"); } } //end of for loop } public static void main(String args[]) { TestThreadInterrupt t1 = new TestThreadInterrupt(); TestThreadInterrupt t2 = new TestThreadInterrupt(); t1.start(); t1.interrupt(); t2.start(); } }
Output: code for interrupted thread code for normal thread code for normal thread code for normal thread
suspend():
You can use it to suspend the thread. [deprecated]
resume():
You can use it to resume the suspended thread. [deprecated]
stop():
You can use it to halt the thread. [deprecated]
Note: Sun has deprecated a variety of Thread methods, such as suspend(), resume() and stop() because they can lock up your programs or damage objects. As a result, you should not call them in your code.
We’ve covered almost all the important areas of the Java Thread class in the above section, hope it will help. In the next segment, you’ll see the two methods to create threads in Java.
Create a Thread by Extending the Thread Class
In this case, you need to complete the following steps to spawn a thread in a Java program.
- Add a new class that extends the Thread class.
- This newly created class should override the Run() method which is the entry point for the new thread.
- Invokes the start() method to initiate the execution of the thread.
Check out the below sample code:
package com.techbeamers.multithreading; class MultithreadDemo extends Thread{ public void run(){ System.out.println("My thread is in running state."); } public static void main(String args[]){ MultithreadDemo obj=new MultithreadDemo(); obj.start(); } }
Output: My thread is in running state
Create a Thread by Using the Runnable Interface
For this approach, you need to follow the below steps to create a thread.
- Create a class that does the following.
- Implements the Runnable interface
- Provides the implementation of the run() method
- The “run()” function is an entry point for the thread, and it remains alive until the “run()” function finishes its execution.
- Once you create the thread, bring it to the Running state by calling the start() method.
- Note: The start() method calls the run() method implicitly.
Check out the below sample code:
package com.techbeamers.multithreading; class MultithreadDemo implements Runnable{ public void run(){ System.out.println("My thread is in running state."); } public static void main(String args[]){ MultithreadDemo obj=new MultithreadDemo(); Thread threadobj = new Thread(obj); threadobj.start(); } }
Output: My thread is in running state
Multithreading Quiz – Must Attempt
Here is a Java multithreading quiz empowered with 20 exciting and challenging questions for programmers. Have a look:
Download Java Multithreading Samples
Now it’s time to download the sample projects so that you can easily understand the Java multithreading code snippets specified in this post. Please use the below link to start your download.
- Download Java Multithreading Sample Project.
Summary – Java Multithreading
We hope this Java multithreading tutorial has helped you learn more about multithreading in Java. In our next article, we will discuss different ways to implement synchronization in Java applications.
Enjoy Coding,
TechBeamers