Java Thread is a basic of a multithreading program.
This article is the first part of Java concurrency topics.
I’ll give answers to the following interview questions:
- How to create a thread in Java?
- What is a Thread Lifecycle?
- How to prioritize thread execution?
- How to stop a thread in Java?
- What is a daemon thread?
- How to handle InterruptedException?
- How to handle exceptions outside of the thread?
I’ll write a simple thread program in Java to show how does it work.
Using Threads in Java
Programmers are using threads in Java to execute a piece of code in an asynchronous way.
There are 2 ways how to create a thread in Java:
- Create a child of
Thread
class - Implement
Runnable
interface
The 2nd one is a more flexible way because you don’t have inheritance restrictions.
Create a Sub-class of a Thread
Let’s implement a TransactionThread
that extends Thread
class.
Imagine it executes bank transaction.
It accepts transaction id via the constructor and I want to print it during execution.
Example:
package com.explainjava;
public class TransactionThread extends Thread {
private final int id;
public TransactionThread(int id) {
this.id = id;
}
@Override
public void run() {
System.out.println("EXECUTE CONCURRENT TRANSACTION #" + id);
}
}
You should override method run()
and put your code there.
I want to execute 10 concurrent transactions.
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new TransactionThread(i).start();
}
}
i
variable is an id of the transaction.
Output:
EXECUTE CONCURRENT TRANSACTION #0
EXECUTE CONCURRENT TRANSACTION #4
EXECUTE CONCURRENT TRANSACTION #3
EXECUTE CONCURRENT TRANSACTION #2
EXECUTE CONCURRENT TRANSACTION #6
EXECUTE CONCURRENT TRANSACTION #1
EXECUTE CONCURRENT TRANSACTION #7
EXECUTE CONCURRENT TRANSACTION #5
EXECUTE CONCURRENT TRANSACTION #8
EXECUTE CONCURRENT TRANSACTION #9
As you can see threads were executed in a different order.
JVM doesn’t guarantee threads execution order.
Implement a Runnable interface
Another way to create a new thread is to implement Runnable
interface.
It’s doing the same as in the example above.
package com.explainjava;
public class TransactionRunner implements Runnable {
private final int id;
public TransactionRunner(int id) {
this.id = id;
}
@Override
public void run() {
System.out.println("EXECUTE CONCURRENT TRANSACTION #" + id);
}
}
Execution looks like this:
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
Thread thread = new Thread(new TransactionRunner(i));
thread.start();
}
}
Output:
EXECUTE CONCURRENT TRANSACTION #0
EXECUTE CONCURRENT TRANSACTION #4
EXECUTE CONCURRENT TRANSACTION #5
EXECUTE CONCURRENT TRANSACTION #3
EXECUTE CONCURRENT TRANSACTION #6
EXECUTE CONCURRENT TRANSACTION #2
EXECUTE CONCURRENT TRANSACTION #1
EXECUTE CONCURRENT TRANSACTION #8
EXECUTE CONCURRENT TRANSACTION #7
EXECUTE CONCURRENT TRANSACTION #9
Again threads executed in a different order.
How to Create a Thread in Java 8
In general, it’s a combination of implementing Runnable
interface and Java 8 lambda.
Example:
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
int transactionId = i;
Thread thread = new Thread(() -> System.out.println("EXECUTE CONCURRENT TRANSACTION #" + transactionId));
thread.start();
}
}
Looks even better than first two solutions, but it’s a little bit complicated to test piece of code inside of the thread.
If you have encapsulated code in separate class you can easily write unit tests for it.
I copied i variable because local variables referenced from a lambda expression must be final or effectively final.
Java Thread Lifecycle
There are 6 possible thread states in Java.
New | Thread is created but not started yet. |
Runnable | Thread is executing, but it may be waiting for system resources, e.g. processor. |
Blocked | Thread is waiting for monitor lock to enter a synchronized block or method. |
Waiting | Thread is waiting for another thread action. It can happen if you’re using: Object.wait() , Thread.join() or LockSupport.part() methods. For example. a thread called Object.wait() on an object is waiting for another thread call Object.notify() or Object.notifyAll() on that object. |
Timed Waiting | The same as waiting but with specified waiting time. The following methods can do that: Thread.sleep() , Object.wait(long) , Thread.join(long) , LockSupport.parkNanos() and LockSupport.partUntil() |
Terminated | Execution is finished |
So lifecycle can be the following:
- New
- Runnable
- Blocked, waiting or timed waiting
- Terminated
3rd point is optional.
How to Set Thread Priority
As I mentioned before JVM doesn’t guarantee threads execution order.
One way to impact an order is to specify a priority.
You can invoke method:
public final void setPriority(int newPriority)
So threads with a higher priority are executed in preference to threads with lower priority.
Thread
class defined 3 constants:
/**
* The minimum priority that a thread can have.
*/
public static final int MIN_PRIORITY = 1;
/**
* The default priority that is assigned to a thread.
*/
public static final int NORM_PRIORITY = 5;
/**
* The maximum priority that a thread can have.
*/
public static final int MAX_PRIORITY = 10;
As you can see minimum priority is 1 and maximum is 10.
If you invoke setPriority(int newPriority)
method with out of the range value – IllegalArgumentException
will be thrown.
Max thread priority can’t be higher than thread group max priority as well.
How to Stop Thread
The preferable way to stop a thread in Java is to use isInterrupted()
and interrupt()
methods of a Thread
class.
Example:
package com.explainjava;
public class ThreadRunner implements Runnable {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("EXECUTE THREAD");
}
}
}
We have a code that executes all time while the thread is not interrupted.
I want to start a thread, wait a little bit until it’s working and then stop it.
public static void main(String[] args) throws InterruptedException {
System.out.println("START THREAD");
Thread thread = new Thread(new ThreadRunner());
thread.start();
System.out.println("WAIT A LITTLE BIT");
Thread.sleep(100L);
thread.interrupt();
System.out.println("THREAD IS STOPPED");
}
So the mechanism is simple:
- Use
isInterrupted()
method inside of your thread to check is current thread interrupted or not - Invoke
thread.interrupt()
when you want to stop a thread
What Is a Daemon Thread?
Your program will work until at least one thread is alive.
But what if I want to stop the program when the main thread is stopped?
You have to mark a thread as a daemon.
Example:
package com.explainjava;
public class ThreadRunner implements Runnable {
@Override
public void run() {
while (true) {
System.out.println("EXECUTE THREAD");
}
}
public static void main(String[] args) {
System.out.println("START THREAD");
Thread thread = new Thread(new ThreadRunner());
thread.start();
}
}
This program will never stop.
You should do it manually.
To fix it we need to set daemon as true
:
public static void main(String[] args) {
System.out.println("START THREAD");
Thread thread = new Thread(new ThreadRunner());
thread.setDaemon(true);
thread.start();
}
Now the new thread is marked as a daemon and it will finish its work when the main thread will be finished.
How To Catch Exception From Another Thread
For example, you started a thread and you want to handle an exception that occurred inside.
You can do it using uncaught exception handler.
Example:
package com.explainjava;
public class ThreadRunner implements Runnable {
@Override
public void run() {
throw new IllegalArgumentException("Something went wrong");
}
public static void main(String[] args) {
System.out.println("START THREAD");
Thread thread = new Thread(new ThreadRunner());
thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("EXCEPTION MESSAGE: " + e.getMessage());
}
});
thread.start();
}
}
Thread throws an exception during execution.
We catch this exception in UncaughtExceptionHandler
and print its message.
What Is a Java InterruptedException And How To Handle It?
This exception is thrown when a thread is waiting or sleeping and thread is interrupted during or before this process.
I found 287 methods that throw this exception in Java 9.
The most important methods that you should know is:
- Object.wait()
- Thread.sleep()
- Thread.joint()
The best practice to handle it is to mark a current thread as interrupted.
Example:
package com.explainjava;
public class ThreadRunner implements Runnable {
@Override
public void run() {
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
}
}
Conclusion
I explained the most important information about threads in Java, but the most complicated part is synchronization between multiple threads.
I’ll write about it in one of the future articles.
I hope you’ve got answers to the most popular interview questions about threads in Java.
If not – ask questions in comments.