Java Threads Tutorial: Page 4 of 5

  • If a thread has been put to sleep, then the specified number of milliseconds must elapse (or it must be interrupted).
  • If a thread has been suspended, then its resume() method must be invoked
  • If a thread is waiting on a condition variable, whatever object owns the variable must relinquish it by calling
    either notify() or notifyAll().
  • If a thread is blocked on I/O, then the I/O must complete.

    DEAD STATE

    A thread enters this state when the run() method has finished executing or when the stop() method is invoked. Once in this state, the thread cannot ever run again.

THREAD PRIORITY

In Java we can specify the priority of each thread relative to other threads. Those threads having higher
priority get greater access to available resources then lower priority threads. A Java thread inherits its priority
from the thread that created it. Heavy reliance on thread priorities for the behavior of a program can make the
program non portable across platforms, as thread scheduling is host platform–dependent.

You can modify a thread’s priority at any time after its creation using the setPriority() method and retrieve
the thread priority value using getPriority() method.

The following static final integer constants are defined in the Thread class:

MIN_PRIORITY (0) Lowest Priority NORM_PRIORITY (5) Default Priority MAX_PRIORITY (10) Highest Priority

1. 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.
2. The waiting thread times out.
3. Another thread interrupts the waiting thread.

Notify

Invoking the notify() method on an object wakes up a single thread that is waiting on the lock of this object.
A call to the notify() method has no consequences if there are no threads in the wait set of the object.
The notifyAll() method wakes up all threads in the wait set of the shared object.

Below program shows three threads, manipulating the same stack. Two of them are pushing elements on the stack, while the third one is popping elements off the stack. This example illustrates how a thread waiting as a result of calling the wait() method on an object, is notified by another thread calling the notify() method on the same object

THREAD SCHEDULER

Schedulers in JVM implementations usually employ one of the two following strategies:

Preemptive scheduling

If a thread with a higher priority than all other Runnable threads becomes Runnable, the scheduler will
preempt the running thread (is moved to the runnable state) and choose the new higher priority thread for execution.

Time-Slicing or Round-Robin scheduling

A running thread is allowed to execute for a fixed length of time (a time slot it’s assigned to), after which it moves to the Ready-to-run state (runnable) to await its turn to run again.

A thread scheduler is implementation and platform-dependent; therefore, how threads will be scheduled is unpredictable across different platforms.

YIELDING

A call to the static method yield(), defined in the Thread class, will cause the current thread in the Running state to move to the Runnable state, thus relinquishing the CPU. The thread is then at the mercy of the thread scheduler as to when it will run again. If there are no threads waiting in the Ready-to-run state, this thread continues execution. If there are other threads in the Ready-to-run state, their priorities determine which thread gets to execute. The yield() method gives other threads of the same priority a chance to run. If there are no equal priority threads in the “Runnable” state, then the yield is ignored.

SLEEPING AND WAKING UP

The thread class contains a static method named sleep() that causes the currently running thread to pause its execution and transit to the Sleeping state. The method does not relinquish any lock that the thread might have. The thread will sleep for at least the time specified in its argument, before entering the runnable state where it takes its turn to run again. If a thread is interrupted while sleeping, it will throw an InterruptedException when it awakes and gets to execute. The Thread class has several overloaded versions of the sleep() method.

WAITING AND NOTIFYING

Waiting and notifying provide means of thread inter-communication that synchronizes on the same object. The threads execute wait() and notify() (or notifyAll()) methods on the shared object for this purpose. The notifyAll(), notify() and wait() are methods of the Object class. These methods can be invoked only from within a synchronized context (synchronized method or synchronized block), otherwise, the call will result in an IllegalMonitorStateException. The notifyAll() method wakes up all the threads waiting on the resource. In this situation, the awakened threads compete for the resource. One thread gets the resource and the others go back to waiting.

wait() method signatures

final void wait(long timeout) throws InterruptedException
final void wait(long timeout, int nanos) throws InterruptedException
final void wait() throws InterruptedException

The wait() call can specify the time the thread should wait before being timed out. An another thread can invoke an interrupt() method on a waiting thread resulting in an InterruptedException. This is a checked exception and hence the code with the wait() method must be enclosed within a try catch block.

notify() method signatures

final void notify()
final void notifyAll()

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. The releasing of the lock of the shared object by the thread allows other threads to run and execute synchronized code on the same object after acquiring its lock.
The wait() method causes the current thread to wait until another thread notifies it of a condition change.

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

1. 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.
2. The waiting thread times out.
3. Another thread interrupts the waiting thread.

Notify

Invoking the notify() method on an object wakes up a single thread that is waiting on the lock of this object.
A call to the notify() method has no consequences if there are no threads in the wait set of the object.
The notifyAll() method wakes up all threads in the wait set of the shared object.

Below program shows three threads, manipulating the same stack. Two of them are pushing elements on the stack, while the third one is popping elements off the stack. This example illustrates how a thread waiting as a result of calling the wait() method on an object, is notified by another thread calling the notify() method on the same object

 

 
class StackClass {

	private Object[] stackArray;
	private volatile int topOfStack;
	StackClass(int capacity) {
		stackArray = new Object[capacity];
		topOfStack = -1;
	}
	public synchronized Object pop() {
		System.out.println(Thread.currentThread() + ": popping");
		while (isEmpty()) {
			try {
				System.out.println(Thread.currentThread()
						+ ": waiting to pop");
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		Object obj = stackArray[topOfStack];
		stackArray[topOfStack--] = null;
		System.out.println(Thread.currentThread()
				+ ": notifying after pop");
		notify();
		return obj;
	}
	public synchronized void push(Object element) {
		System.out.println(Thread.currentThread() + ": pushing");
		while (isFull()) {
			try {
				System.out.println(Thread.currentThread()
						+ ": waiting to push");
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		stackArray[++topOfStack] = element;
		System.out.println(Thread.currentThread()
				+ ": notifying after push");
		notify();
	}
	public boolean isFull() {
		return topOfStack >= stackArray.length - 1;
	}
	public boolean isEmpty() {
		return topOfStack < 0;
	}
}

abstract class StackUser extends Thread {

	protected StackClass stack;
	StackUser(String threadName, StackClass stack) {
		super(threadName);
		this.stack = stack;
		System.out.println(this);
		setDaemon(true);
		start();
	}
}

class StackPopper extends StackUser { // Stack Popper

	StackPopper(String threadName, StackClass stack) {
		super(threadName, stack);
	}
	public void run() {
		while (true) {
			stack.pop();
		}
	}
}

class StackPusher extends StackUser { // Stack Pusher

	StackPusher(String threadName, StackClass stack) {
		super(threadName, stack);
	}
	public void run() {
		while (true) {
			stack.push(new Integer(1));
		}
	}
}

public class WaitAndNotifyExample {

	public static void main(String[] args) {
		StackClass stack = new StackClass(5);
		new StackPusher("One", stack);
		new StackPusher("Two", stack);
		new StackPopper("Three", stack);
		System.out.println("Main Thread sleeping.");
		try {
			Thread.sleep(500);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("Exit from Main Thread.");
	}
}

Download Wait Notify methods Thread Program Example

The field topOfStack in class StackClass is declared volatile, so that read and write operations on this variable will access the master value of this variable, and not any copies, during runtime.
Since the threads manipulate the same stack object and the push() and pop() methods in the class StackClassare synchronized, it means that the threads synchronize on the same object.

 

How the program uses wait() and notify() for inter thread communication.

 

(1) The synchronized pop() method – When a thread executing this method on the StackClass object finds that the stack is empty, it invokes the wait() method in order to wait for some other thread to fill the stack by using the synchronized push. Once an other thread makes a push, it invokes the notify method.


(2)The synchronized push() method – When a thread executing this method on the StackClass object finds that the stack is full, i t invokes the wait() method to await some other thread to remove an element to provide space for the newly to be pushed element.
Once an other thread makes a pop, it invokes the notify method.

Like us on Facebook