Concurrency : Thread states

Concurrency2ThreadStates

The Thread class provides the getState() method to determine the state of the current thread.  e. A thread can be in one of the following states:

  • NEW – A thread that has not yet started is in this state.
  • RUNNABLE – A

    thread executing in the Java virtual machine is in this state.

  • BLOCKED –

    A thread that is blocked waiting for a monitor lock is in this state.

  • WAITING –

    A thread that is waiting indefinitely for another thread to perform a particular action is in this state.

  • TIMED_WAITING –

    A thread that is waiting for another thread to perform an action for up to a specified waiting time is in this state.

  • TERMINATED – A

     thread that has exited is in this state.

Running and Yielding

By calling the static method yield(), the running thread gives other threads in the Readytorun state a chance to run. The yield()  method is also an advisory method, and therefore comes with no guarantees that the JVM will carry out the call’s bidding. A call to the yield() method does not affect any locks that the thread might hold.
A typical example where this can be useful is when a user has given some command to start a CPUintensive computation, and has the option of cancelling it by clicking on a CANCEL button. If the computation thread hogs the CPU and the user clicks the CANCEL button, chances are that it might take a while before the thread monitoring the user input gets a chance to run and take appropriate action to stop the computation. A thread running such a computation should do the computation in increments, yielding between increments to allow other threads to run.

Sleeping and Waking Up

A call to the static method sleep() in the Thread class will cause the currently running thread to temporarily pause its execution and transit to the Sleeping state. This method does not relinquish any lock that the thread might have.If a thread is interrupted while sleeping, it will throw an InterruptedException.

Waiting and Notifying

These methods can only be executed on an object whose lock the thread holds (in other words, in synchronized code), otherwise, the call will result in an IllegalMonitorStateException. Communication between threads is facilitated by waiting and notifying. A thread usually calls the wait() method on the object whose lock it holds because a condition for its continued execution was not met. The thread leaves the Running state and transits to the Waiting-for-notification state. There it waits for this condition to occur. The thread relinquishes ownership of the object lock.
Transition to the Waiting-for-notification state and relinquishing the object lock are completed as one atomic (non-interruptible) operation. Note that the waiting thread relinquishes only the lock of the object on which the wait() method was invoked. It does not relinquish any other object locks that it might hold, which will remain locked while the thread is waiting.

A thread in the Waiting-for-notification state can be awakened by the occurrence of any one of these three incidents:

  • Another thread invokes the notify() method on the object of the waiting thread, and the waiting thread is selected as the thread to be awakened.
  • The waiting thread times out.
  • Another thread interrupts the waiting thread.

Multithreading replaces event loop programming by dividing your tasks into discrete and logical units. Threads also provide a secondary benefit: they do away with polling. Polling is usually implemented by a loop that is used to check some condition repeatedly. Once the condition is true, appropriate action is taken. This wastes CPU time. For example, consider the classic queuing problem, where one thread is producing some data and another is consuming it. To make the problem more interesting, suppose that the producer has to wait until the consumer is finished before it generates more data. In a polling system, the
consumer would waste many CPU cycles while it waited for the producer to produce. Once the producer was finished, it would start polling, wasting more CPU cycles waiting for the consumer to finish, and so on. Clearly, this situation is undesirable.

To avoid polling, Java includes an elegant interprocess communication mechanism via the wait( ), notify( ), and notifyAll( ) methods. These methods are implemented as final methods in Object, so all classes have them. All three methods can be called only from within a synchronized method/block.

  • wait( ) tells the calling thread to give up the monitor and go to sleep until some other thread enters the same monitor and calls notify( ). Additional forms of wait( ) exist that allow you to specify a period of time to wait.
  • notify( ) wakes up the first thread that called wait( ) on the same object.
  • notifyAll( ) wakes up all the threads that called wait( ) on the same object. The highest priority thread will run first.

Lets take an example:


package mynotes.concurrency.basic;

import java.util.Scanner;

public class WaitNotifyExample {

Object myMonitorObject = new Object();

public void produce() throws InterruptedException {
 synchronized (myMonitorObject) {
 System.out.println("produce method running...");
 myMonitorObject.wait();
 System.out.println("produce method RESUMED...");
 }
 }

public void consumes() throws InterruptedException {
 Scanner scanner = new Scanner(System.in);

synchronized (myMonitorObject) {
 System.out.println("consumes method running...");
 scanner.nextLine();
 System.out.println("Consume method- returned key pressed");
 myMonitorObject.notify();
 }
 }

}

Following is our main class that creates 2 threads and runs produce and consume methods.


package mynotes.concurrency.basic;

public class WaitNotifyExampleMain {

public static void main(String[] args) {
 final WaitNotifyExample aWaitNotifyExample = new WaitNotifyExample();
 Thread t1 = new Thread(new Runnable() {

@Override
 public void run() {
 try {
 aWaitNotifyExample.produce();
 } catch (InterruptedException e) {
 e.printStackTrace();
 }

}
 });

Thread t2 = new Thread(new Runnable() {

@Override
 public void run() {
 try {
 aWaitNotifyExample.consumes();
 } catch (InterruptedException e) {
 e.printStackTrace();
 }

}
 });

t1.start();
 t2.start();

try {
 t1.join();
 t2.join();

} catch (InterruptedException e) {
 e.printStackTrace();
 }

}

}

Output:


produce method running...
consumes method running...

Consume method- returned key pressed
produce method RESUMED...

In the above example, we created 2 threads, one calls produce() method of the WaitNotifyExample class and the other calls consume() of the same class. Both method have a synchronized code block. Both synchronized code blocks use the same monitor object, so one thread has to wait while other thread has the lock. Here the produce() method takes the lock and call wait() on the object of which it holds the lock. This will trigger the thread to relinquish the lock on the monitor object and wait until it gets notified. Now the  thread 2 will run and now waits for ‘Returned’ key to be pressed. On pressing return key it calls the notify() on the monitor object which wakes the t1 thread which starts to look for lock acquisition on the monitor object. t2 then completes and relinquishes the lock, which is then acquired by t1 and is then resumed.

Missed Signals – The above example have a bug. We assumed that t1 will run first and call wait() and then t2 will run. What if  a thread (t2) calls notify() before the thread to signal (t1) has called wait(), the signal will be missed by the waiting thread. This may or may not be a problem (like if wait(time) is called or likewise), but in some cases this may result in the waiting thread waiting forever, never waking up, because the signal to wake up was missed.  Lets make some changes in out previous code to handle this:


package mynotes.concurrency.basic;

import java.util.Scanner;

public class WaitNotifyExample {

Object myMonitorObject = new Object();
 boolean signal = false;

public void produce() throws InterruptedException {
 synchronized (myMonitorObject) {
 System.out.println("produce method running...");
 if(!signal){
 myMonitorObject.wait();
 }
 System.out.println("produce method RESUMED...");
 signal=false;
 }
 }

public void consumes() throws InterruptedException {
 Scanner scanner = new Scanner(System.in);

synchronized (myMonitorObject) {
 System.out.println("consumes method running...");
 signal=true;
 scanner.nextLine();
 System.out.println("Consume method- returned key pressed");
 myMonitorObject.notify();
 }
 }

}

Notice the boolean variable. There could be more adjustment made in the code but this was just to give you an mental note while dealing with threads.

Why wait, notify and notifyAll is defined in Object Class and not on Thread class?
Locks are made available on per Object basis, which is another reason wait and notify is declared in Object class rather then Thread class. If wait() and notify() were on the Thread class instead then each thread would have to know the status of every other thread. How would thread1 know that thread2 was waiting for access to a particular resource? If t1 needed to call t2.notify() it would have to somehow find out that t2 was waiting. There would need to be some mechanism for threads to register the resources or actions that they need so others could signal them when stuff was ready or available. Thus they are the communication mechanism between two threads in Java and Object class is correct place to make them available for every object

Blocking for I/O
A running thread, on executing a blocking operation requiring a resource (like a call to an I/O method), will transit to the BlockedforI/O state. The blocking operation must complete before the thread can proceed to the Ready-to-run state.

Joining
A thread can invoke the overloaded method join() on another thread in order to wait for the other thread to complete its execution before continuing. A running thread t1 invokes the method join() on a thread t2. The join() call has no effect if thread t2 has already completed. If thread t2 is still alive, thread t1 transits to the Blocked-for-join-completion state. Thread t waits in this state until one of these events occur:

  • Thread t2 completes : In this case thread t1 moves to the Ready-to-run state, and when it gets to run, it will continue normally after the call to the join() method.
  • Thread t1 is timed out : The time specified in the argument of the join() method call has elapsed without thread t2 completing. In this case as well, thread t1 transits to the Ready-to-run state. When it gets to run, it will continue normally after the call to the join() method.
  • Thread t1 is interrupted : Some thread interrupted thread t1 while thread t1 was waiting for join completion. Thread t1 transits to the Ready-to-run state, but when it gets to execute, it will now throw an InterruptedException.

Deadlocks
A deadlock is a situation where a thread is waiting for an object lock that another thread holds, and this second thread is waiting for an object lock that the first thread holds. Since each thread is waiting for the other thread to relinquish a lock, they both remain waiting forever in the Blocked-for-lock-acquisition state. The threads are said to be deadlocked. Lets see this from an example:


package mynotes.concurrency.basic;

public class DeadLockExample {

public static void main(String[] args){
 //These are the two resource objects we'll try to get locks for
 final Object resource1 = "resource1";
 final Object resource2 = "resource2";
 //Here's the first thread. It tries to lock resource1 then resource2
 Thread t1 = new Thread() {
 public void run() {
 //Lock resource 1
 synchronized(resource1){
 System.out.println("Thread 1: locked resource 1");
 try{
 Thread.sleep(50);
 } catch (InterruptedException e) {}

//Now wait 'till we can get a lock on resource 2
 synchronized(resource2){
 System.out.println("Thread 1: locked resource 2");
 }
 }
 }
 };

//Here's the second thread. It tries to lock resource2 then resource1
 Thread t2 = new Thread(){
 public void run(){
 //This thread locks resource 2 right away
 synchronized(resource2){
 System.out.println("Thread 2: locked resource 2");
 //Then it pauses, for the same reason as the first thread does
 try{
 Thread.sleep(50);
 } catch (InterruptedException e){}
 synchronized(resource1){
 System.out.println("Thread 2: locked resource 1");
 }
 }
 }
 };

//Start the two threads.
 t1.start();
 t2.start();

 try {
 t1.join();
 t2.join();

} catch (InterruptedException e) {
 e.printStackTrace();
 }
 System.out.println("Programm finished");
 }
 }

Output:


Thread 1: locked resource 1
Thread 2: locked resource 2

Notice that the sysout ‘Programm finished’ is never printed. However, the potential of deadlock in the situation is easy to fix. If the two threads acquire the locks on the objects in the same order, then mutual lock dependency is avoided and a deadlock can never occur. The cause of a deadlock is not always easy to discover, let alone easy to fix.

Grab all the code from my GitHub repository.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: