Java Threads
Contents
- 1 Life Cycle of a Thread
- 1.1 Thread States
- 1.2 Thread Priorities
- 1.3 Runnable Interface
- 1.4 Thread Class
- 1.5 Thread Methods
- 1.5.1 public void start()
- 1.5.2 public void run()
- 1.5.3 public final void setName(String name)
- 1.5.4 public final void setPriority(int priority)
- 1.5.5 public final void setDaemon(boolean on)
- 1.5.6 public final void join(long millisec) - t1.join(2000);//start second thread after waiting for 2 seconds or if it's dead
- 1.5.7 public void interrupt()
- 1.5.8 public final boolean isAlive() - It tests if this thread is alive
- 1.5.9 public static void yield()
- 1.5.10 public static void sleep(long millisec)
- 1.5.11 public static boolean holdsLock(Object x)
- 1.5.12 public static Thread currentThread()
- 1.5.13 public static void dumpStack()
- 2 Multithreading Interview Questions and Answers
- 2.1 What is the difference between processes and threads ?
- 2.2 Explain different ways of creating a thread.Which one would you prefer and why ?
- 2.3 Explain the available thread states in a high-level?
- 2.4 What is the difference between a synchronized method and a synchronized block ?
- 2.5 What’s a deadlock ?
- 2.6 Java Examples - Monitoring a Thread
- 2.7 What is wrong with this code? Heap Vs Stack, Thread safety & Synchronized
Life Cycle of a Thread
Thread States
Following are the stages of the life cycle
NEW
A new thread begins its life cycle in the new state. It remains in this state until the program starts the thread. It is also referred to as a born thread.
RUNNABLE
After a newly born thread is started, the thread becomes runnable. A thread in this state is considered to be executing its task.
RUNNING
BLOCKED/WAITING
Sometimes, a thread transitions to the waiting state while the thread waits for another thread to perform a task. A thread transitions back to the runnable state only when another thread signals the waiting thread to continue executing.
A runnable thread can enter the timed waiting state for a specified interval of time. A thread in this state transitions back to the runnable state when that time interval expires or when the event it is waiting for occurs.
TERMINATED/DEAD
A runnable thread enters the terminated state when it completes its task or otherwise terminates.
Thread Priorities
Every Java thread has a priority that helps the operating system determine the order in which threads are scheduled.
Java thread priorities are in the range between MIN_PRIORITY (a constant of 1) and MAX_PRIORITY (a constant of 10). By default, every thread is given priority NORM_PRIORITY (a constant of 5).
Threads with higher priority are more important to a program and should be allocated processor time before lower-priority threads. However, thread priorities cannot guarantee the order in which threads execute and are very much platform dependent.
Runnable Interface
Create a Thread by Implementing a Runnable Interface
If your class is intended to be executed as a thread then you can achieve this by implementing a Runnable interface. You will need to follow three basic steps:
- Step 1:As a first step, you need to implement a run() method provided by a Runnable interface. This method provides an entry point for the thread and you will put your complete business logic inside this method. Following is a simple syntax of the run() method
public void run( )
- Step 2: As a second step, you will instantiate a Thread object using the following constructor
Thread(Runnable threadObj, String threadName);
Where, threadObj is an instance of a class that implements the Runnable interface and threadName is the name given to the new thread.
- Step 3:Once a Thread object is created, you can start it by calling start() method, which executes a call to run( ) method. Following is a simple syntax of start() method
void start();
Example:
class RunnableDemo implements Runnable {
private Thread t;
private String threadName;
RunnableDemo( String name) {
threadName = name;
System.out.println("Creating " + threadName );
}
public void run() {
System.out.println("Running " + threadName );
try {
for(int i = 4; i > 0; i--) {
System.out.println("Thread: " + threadName + ", " + i);
// Let the thread sleep for a while.
Thread.sleep(50);
}
} catch (InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread " + threadName + " exiting.");
}
public void start () {
System.out.println("Starting " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
}
public class TestThread {
public static void main(String args[]) {
RunnableDemo R1 = new RunnableDemo( "Thread-1");
R1.start();
RunnableDemo R2 = new RunnableDemo( "Thread-2");
R2.start();
}
}
This will produce the following result
Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.
Thread Class
Create a Thread by Extending a Thread Class
The second way to create a thread is to create a new class that extends Thread class using the following two simple steps. This approach provides more flexibility in handling multiple threads created using available methods in Thread class.
- Step 1:You will need to override run( ) method available in Thread class. This method provides an entry point for the thread and you will put your complete business logic inside this method. Following is a simple syntax of run() method
public void run( )
- Step 2:
Once Thread object is created, you can start it by calling start() method, which executes a call to run( ) method. Following is a simple syntax of start() method
void start( );
Example
class ThreadDemo extends Thread {
private Thread t;
private String threadName;
ThreadDemo( String name) {
threadName = name;
System.out.println("Creating " + threadName );
}
public void run() {
System.out.println("Running " + threadName );
try {
for(int i = 4; i > 0; i--) {
System.out.println("Thread: " + threadName + ", " + i);
// Let the thread sleep for a while.
Thread.sleep(50);
}
} catch (InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread " + threadName + " exiting.");
}
public void start () {
System.out.println("Starting " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
}
public class TestThread {
public static void main(String args[]) {
ThreadDemo T1 = new ThreadDemo( "Thread-1");
T1.start();
ThreadDemo T2 = new ThreadDemo( "Thread-2");
T2.start();
}
}
This will produce the following result
Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.
Thread Methods
public void start()
Starts the thread in a separate path of execution, then invokes the run() method on this Thread object.
public void run()
If this Thread object was instantiated using a separate Runnable target, the run() method is invoked on that Runnable object.
public final void setName(String name)
Changes the name of the Thread object. There is also a getName() method for retrieving the name.
public final void setPriority(int priority)
Sets the priority of this Thread object. The possible values are between 1 and 10.
public final void setDaemon(boolean on)
A parameter of true denotes this Thread as a daemon thread.
public final void join(long millisec) - t1.join(2000);//start second thread after waiting for 2 seconds or if it's dead
The current thread invokes this method on a second thread, causing the current thread to block until the second thread terminates or the specified number of milliseconds passes.
- public final void join(): This java thread join method puts the current thread on wait until the thread on which it’s called is dead. If the thread is interrupted, it throws InterruptedException.
- public final synchronized void join(long millis): This java thread join method is used to wait for the thread on which it’s called to be dead or wait for specified milliseconds. Since thread execution depends on OS implementation, it doesn’t guarantee that the current thread will wait only for given time.
- public final synchronized void join(long millis, int nanos): This java thread join method is used to wait for thread to die for given milliseconds plus nanoseconds.
Here is a simple example showing usage of Thread join methods:
package com.journaldev.threads;
public class ThreadJoinExample {
public static void main(String[] args) {
Thread t1 = new Thread(new MyRunnable(), "t1");
Thread t2 = new Thread(new MyRunnable(), "t2");
Thread t3 = new Thread(new MyRunnable(), "t3");
t1.start();
//start second thread after waiting for 2 seconds or if it's dead
try {
t1.join(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
//start third thread only when first thread is dead
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
t3.start();
//let all threads finish execution before finishing main thread
try {
t1.join();
t2.join();
t3.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("All threads are dead, exiting main thread");
}
}
class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println("Thread started:::"+Thread.currentThread().getName());
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread ended:::"+Thread.currentThread().getName());
}
}
Output of the above program is:
Thread started:::t1
Thread started:::t2
Thread ended:::t1
Thread started:::t3
Thread ended:::t2
Thread ended:::t3
All threads are dead, exiting main thread
public void interrupt()
Interrupts this thread, causing it to continue execution if it was blocked for any reason.
public final boolean isAlive() - It tests if this thread is alive
Returns true if the thread is alive, which is any time after the thread has been started but before it runs to completion.
It tests if this thread is alive. A thread is alive if it has been started and has not yet died. There is a transitional period from when a thread is running to when a thread is not running. After the run() method returns, there is a short period of time before the thread stops. If we want to know if the start method of the thread has been called or if thread has been terminated, we must use isAlive() method. This method is used to find out if a thread has actually been started and has yet not terminated.
// Java program to illustrate
// isAlive()
public class oneThread extends Thread {
public void run()
{
System.out.println("geeks ");
try {
Thread.sleep(300);
}
catch (InterruptedException ie) {
}
System.out.println("forgeeks ");
}
public static void main(String[] args)
{
oneThread c1 = new oneThread();
oneThread c2 = new oneThread();
c1.start();
c2.start();
System.out.println(c1.isAlive());
System.out.println(c2.isAlive());
}
}
Output:
true
true
geeks
geeks
forgeeks
forgeeks
The previous methods are invoked on a particular Thread object. The following methods in the Thread class are static. Invoking one of the static methods performs the operation on the currently running thread.
public static void yield()
Causes the currently running thread to yield to any other threads of the same priority that are waiting to be scheduled.
public static void sleep(long millisec)
Causes the currently running thread to block for at least the specified number of milliseconds.
public static boolean holdsLock(Object x)
Returns true if the current thread holds the lock on the given Object.
public static Thread currentThread()
Returns a reference to the currently running thread, which is the thread that invokes this method.
public static void dumpStack()
Prints the stack trace for the currently running thread, which is useful when debugging a multithreaded application.
Multithreading Interview Questions and Answers
What is the difference between processes and threads ?
- A process is an execution of a program, while a Thread is a single execution sequence within a process. A process can contain multiple threads. A Thread is sometimes called a lightweight process.
Explain different ways of creating a thread.Which one would you prefer and why ?
- There are three ways that can be used in order for a Thread to be created:
- A class may extend the Thread class.
- A class may implement the Runnable interface.
- An application can use the Executor framework, in order to create a thread pool.
- The Runnable interface is preferred, as it does not require an object to inherit the Thread class. In case your application design requires multiple inheritance, only interfaces can help you. Also, the thread pool is very efficient and can be implemented and used very easily.
- There are three ways that can be used in order for a Thread to be created:
Explain the available thread states in a high-level?
- During its execution, a thread can reside in one of the following states:
- Runnable: A thread becomes ready to run, but does not necessarily start running immediately.
- Running: The processor is actively executing the thread code.
- Waiting: A thread is in a blocked state waiting for some external processing to finish.
- Sleeping: The thread is forced to sleep.
- Blocked on I/O: Waiting for an I/O operation to complete.
- Blocked on Synchronization: Waiting to acquire a lock.
- Dead: The thread has finished its execution.
- During its execution, a thread can reside in one of the following states:
What is the difference between a synchronized method and a synchronized block ?
- In Java programming, each object has a lock. A thread can acquire the lock for an object by using the synchronized keyword. The synchronized keyword can be applied in a method level (coarse grained lock) or block level of code (fine grained lock).
- How does thread synchronization occurs inside a monitor ? What levels of synchronization can you apply ?
- The JVM uses locks in conjunction with monitors. A monitor is basically a guardian that watches over a sequence of synchronized code and ensuring that only one thread at a time executes a synchronized piece of code. Each monitor is associated with an object reference. The thread is not allowed to execute the code until it obtains the lock.
What’s a deadlock ?
- A condition that occurs when two processes are waiting for each other to complete, before proceeding. The result is that both processes wait endlessly.
- How do you ensure that N threads can access N resources without deadlock ?
- A very simple way to avoid deadlock while using N threads is to impose an ordering on the locks and force each thread to follow that ordering. Thus, if all threads lock and unlock the mutexes in the same order, no deadlocks can arise.
Java Examples - Monitoring a Thread
How to monitor a thread's status?
Following example demonstrates how to monitor a thread's status by extending Thread class and using currentThread.getName() method.
class MyThread extends Thread {
boolean waiting = true;
boolean ready = false;
MyThread() {
}
public void run() {
String thrdName = Thread.currentThread().getName();
System.out.println(thrdName + " starting.");
while(waiting) System.out.println("waiting:"+waiting);
System.out.println("waiting...");
startWait();
try {
Thread.sleep(1000);
} catch(Exception exc) {
System.out.println(thrdName + " interrupted.");
}
System.out.println(thrdName + " terminating.");
}
synchronized void startWait() {
try {
while(!ready) wait();
} catch(InterruptedException exc) {
System.out.println("wait() interrupted");
}
}
synchronized void notice() {
ready = true;
notify();
}
}
public class new_class {
public static void main(String args[]) throws Exception {
MyThread thrd = new MyThread();
thrd.setName("MyThread #1");
showThreadStatus(thrd);
thrd.start();
Thread.sleep(50);
showThreadStatus(thrd);
thrd.waiting = false;
Thread.sleep(50);
showThreadStatus(thrd);
thrd.notice();
Thread.sleep(50);
showThreadStatus(thrd);
while(thrd.isAlive())
System.out.println("alive");
showThreadStatus(thrd);
}
static void showThreadStatus(Thread thrd) {
System.out.println(thrd.getName()+" Alive:="+thrd.isAlive()+" State:=" + thrd.getState() );
}
}
Result
The above code sample will produce the following result.
main Alive=true State:=running
What is wrong with this code? Heap Vs Stack, Thread safety & Synchronized
A very simple code that should print numbers from 7 to 21. But does it?
import java.util.concurrent.TimeUnit;
class Counter extends Thread {
//instance variable
Integer count = 0;
// method where the thread execution will start
public void run() {
int fixed = 6; //local variable
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName() + ": result="
+ performCount(fixed));
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// let’s see how to start the threads
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName() + " is executing..." );
Counter counter = new Counter();
//5 threads
for (int i = 0; i < 5; i++) {
Thread t = new Thread(counter);
t.start();
}
}
//multiple threads can access me concurrently
private int performCount(int fixed) {
return (fixed + ++count);
}
}
Above code is NOT Thread-safe If you run it multiple times, you will see that some numbers get repeated as shown below. You get five”15″s and three “12”s. The result will be unpredictable and you will get different results each time you run it.
main is executing...
Thread-1: result=7
Thread-2: result=8
Thread-3: result=9
Thread-4: result=10
Thread-5: result=11
Thread-2: result=12
Thread-3: result=12
Thread-4: result=12
Thread-5: result=13
Thread-1: result=14
Thread-2: result=15
Thread-3: result=15
Thread-4: result=15
Thread-5: result=15
Thread-1: result=15
What is happening under the covers in terms of Heap Vs Stack memory & thread-safety
As shown below in the diagaram, the local variable “fixed”, and the reference “counter” to the instance of the class “Counter” are stored in the stack. The instance of “Counter”, i,e. the object itself is stored in the heap. So, it will be shared by all the threads. The “++count” operation is not atomic and performs 3 operations under the covers:
- Step 1: get value of count from heap
- Step 2: add 1 to count (i.e. count = count + 1)
- Step 3: write the new value back to the heap memory
So, it is possible that 5 threads read the same value of say “count = 8” and increment them all to “9”, and then when added with the fixed value of 6, resulting in five “15”s. Each time you run, you get different results. The above code is unpredictable.
How to fix the concurrency issue?
The above thread safety issue can be fixed two ways by controlling the access to the shared object “counter”.
Solution 1: Synchronized i.e. a lock on the performCount() method
This will put a lock on “counter” object so that when one thread is performing the other threads have to wait for the lock.
import java.util.concurrent.TimeUnit;
class Counter extends Thread {
//instance variable
Integer count = 0;
// method where the thread execution will start
public void run() {
int fixed = 6;
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName() + ": result="
+ performCount(fixed));
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// let’s see how to start the threads
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName() + " is executing..." );
Counter counter = new Counter();
//5 threads
for (int i = 0; i < 5; i++) {
Thread t = new Thread(counter);
t.start();
}
}
private synchronized int performCount(int fixed) {
return (fixed + ++count);
}
}
Output:
main is executing...
Thread-1: result=7
Thread-3: result=8
Thread-2: result=9
Thread-4: result=10
Thread-5: result=11
Thread-4: result=13
Thread-1: result=12
Thread-2: result=14
Thread-3: result=15
Thread-5: result=16
Thread-4: result=18
Thread-3: result=19
Thread-1: result=20
Thread-5: result=21
Thread-2: result=17
Why is locking of a method for thread safety is called “synchronized” and not “locked”?
When a method or block of code is locked with the reserved “synchronized” key word in Java, the memory (i.e. heap) where the shared data is kept is synchronized. This means,
When a synchronized block or method is entered after the lock has been acquired by a thread, it first reads (i.e. synchronizes) any changes to the locked object from the main heap memory to ensure that the thread that has the lock has the current info before start executing.
After the synchronized block has completed and the thread is ready to relinquish the lock, all the changes that were made to the object that was locked is written or flushed back (i.e. synchronized) to the main heap memory so that the other threads that acquire the lock next has the current info.
Solution 2: AtomicInteger so that the increment operation is atomic
The “incrementAndGet()” on AtomicInteger happens atomically so that two or more threads cannot read the same value and increment them to the same result.
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
class Counter extends Thread {
//instance variable
AtomicInteger count = new AtomicInteger();
// method where the thread execution will start
public void run() {
int fixed = 6;
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName() + ": result="
+ performCount(fixed));
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// let’s see how to start the threads
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName() + " is executing..." );
Counter counter = new Counter();
//5 threads
for (int i = 0; i < 5; i++) {
Thread t = new Thread(counter);
t.start();
}
}
private int performCount(int fixed) {
return (fixed + count.incrementAndGet());
}
}
Output:
main is executing...
Thread-1: result=7
Thread-2: result=8
Thread-3: result=9
Thread-4: result=10
Thread-5: result=11
Thread-1: result=16
Thread-3: result=13
Thread-2: result=12
Thread-4: result=15
Thread-5: result=14
Thread-1: result=20
Thread-5: result=19
Thread-2: result=21
Thread-4: result=17
Thread-3: result=18