Author |
Topic: notify() vs notifyAll() -- code examples |
|
EricJ member offline |
|
posts: |
50 |
joined: |
02/22/2007 |
from: |
CA |
|
|
|
|
|
notify() vs notifyAll() -- code examples |
notify() Wakes up a single thread that is waiting on this object's monitor. If any threads are waiting on this object, one of them is chosen to be awakened. The choice is arbitrary and occurs at the discretion of the implementation. A thread waits on an object's monitor by calling one of the wait methods.
notifyAll() Wakes up all threads that are waiting on this object's monitor. A thread waits on an object's monitor by calling one of the wait methods.
|
|
|
|
|
|
|
EricJ member offline |
|
posts: |
50 |
joined: |
02/22/2007 |
from: |
CA |
|
|
|
|
|
Does notifyAll() Really Wake Up All Threads? |
Yes and no. All the waiting threads will wake up, but they will not be able to proceed until: 1) the current thread that called the notifyAll() method relinquishes its monitor; 2) the awakened threads will compete in the usual manner with any other threads to acquire the monitor; 3) the winner that grabs the monitor proceed and then release its monitor for the rest threads; 4) so on so forth, and only one thread can run at a time since only one thread at a time can own an object's monitor.
|
|
|
|
|
|
|
EricJ member offline |
|
posts: |
50 |
joined: |
02/22/2007 |
from: |
CA |
|
|
|
|
|
How Do I Know notify() Wake Up which Thread? |
Never. There is no way to determine which of multiple threads is going to grab the only one notification from notify() method. The Java specification doesn't define which thread gets notified. Which thread actually receives the notification varies based on several factors including the implementation of JVM and scheduling mechanism of platform.
|
|
|
|
|
|
|
EricJ member offline |
|
posts: |
50 |
joined: |
02/22/2007 |
from: |
CA |
|
|
|
|
|
notify() in practice |
/**
*
* A sample code demonstrate how notify() and wait() interact with each other
*
*/
public class ResourcePoolTester extends Thread
{
ResourcePool pool = null;
int num;
public ResourcePoolTester(ResourcePool pool, int num)
{
this.pool = pool;
this.num = num;
}
public synchronized void run()
{
if(num>0){ // check out
System.out.println("Thread [" + Thread.currentThread().getId() +
"] is about to check out resources of: " + num);
pool.checkOut(num);
}else{ // check in
num = -num;
System.out.println("Thread [" + Thread.currentThread().getId() +
"] is about to check in resources of: " + num);
pool.checkIn(num);
}
}
public static void main(String[] args)
{
// initialize the resource pool
ResourcePool pool = new ResourcePool(2);
System.out.println("The pool starts with size of: " + pool.size());
// 5 threads to check out resuorce from the pool
ResourcePoolTester t1 = new ResourcePoolTester(pool, 1);
ResourcePoolTester t2 = new ResourcePoolTester(pool, 2);
ResourcePoolTester t3 = new ResourcePoolTester(pool, 3);
ResourcePoolTester t4 = new ResourcePoolTester(pool, 4);
ResourcePoolTester t5 = new ResourcePoolTester(pool, 5);
t1.start(); // returns immediately
t2.start(); // going to wait
t3.start(); // going to wait
t4.start(); // going to wait
t5.start(); // going to wait
// 2 threads to check in resource into the pool
ResourcePoolTester t6 = new ResourcePoolTester(pool, -6);
t6.start();
try{
Thread.sleep(1000); // just a second
}catch(Exception e){
}
ResourcePoolTester t7 = new ResourcePoolTester(pool, -9);
t7.start();
try{
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
t6.join();
t7.join();
}catch(Exception e){
}
System.out.println("The pool ends up with size of: " + pool.size());
}
}
class ResourcePool
{
/**
* the count monitoring how many resource currently reside in the pool
*/
private int count;
public ResourcePool(int count){
this.count = count;
}
public synchronized void checkOut(int num)
{
// check to see if there are enough resources?
while(count<num){
System.out.println("Thread [" + Thread.currentThread().getId() +
"] is waiting with pool size = " + size());
try{
wait(); // wait until there are enough resources
}catch(Exception e){
}
System.out.println("Thread [" + Thread.currentThread().getId() +
"] wakes up with pool size = " + size());
}
count -= num; // check-out
System.out.println("Thread [" + Thread.currentThread().getId() +
"] returns with pool size = " + size());
}
public synchronized void checkIn(int num)
{
count += num; // check-in
notify();
System.out.println("Thread [" + Thread.currentThread().getId() +
"] checked in with pool size = " + size());
}
public synchronized int size(){
return count;
}
}
Here are the outputs:
The pool starts with size of: 2 Thread [7] is about to check out resources of: 1 Thread [7] returns with pool size = 1 Thread [8] is about to check out resources of: 2 Thread [8] is waiting with pool size = 1 Thread [9] is about to check out resources of: 3 Thread [9] is waiting with pool size = 1 Thread [10] is about to check out resources of: 4 Thread [10] is waiting with pool size = 1 Thread [11] is about to check out resources of: 5 Thread [11] is waiting with pool size = 1 Thread [12] is about to check in resources of: 6 Thread [12] checked in with pool size = 7 Thread [8] wakes up with pool size = 7 Thread [8] returns with pool size = 5 Thread [13] is about to check in resources of: 9 Thread [13] checked in with pool size = 14 Thread [9] wakes up with pool size = 14 Thread [9] returns with pool size = 11
Observations: t1-Thread[7] checks out resource immediately since there are enough (2) resources for what it is asking (1); t2-Thread[8] ~ t5-Thread[11] have to wait until more resources are available; after t6-Thread[12] checks in 6 resources, its notification gets only one thread t2-Thread[8] wake up even though there are enough resources (5 left) in the pool for t3-Thread[9] (it ask for 3), t4-Thread[10] (it asks for 4) or t5-Thread[11] (it asks for 5) to check out; likewise, t7-Thread[13]'s check-in notify() only one thread t3-Thread[9]; t4-Thread[10] and t5-Thread[11] never have a chance to wake up and they may hang forever for the given scenario;
|
|
|
|
|
|
|
EricJ member offline |
|
posts: |
50 |
joined: |
02/22/2007 |
from: |
CA |
|
|
|
|
|
notifyAll() in practice |
/**
*
* A sample code demonstrate how notifyAll() and wait() interact with each other
*
*/
public class ResourcePoolTester extends Thread
{
ResourcePool pool = null;
int num;
public ResourcePoolTester(ResourcePool pool, int num)
{
this.pool = pool;
this.num = num;
}
public synchronized void run()
{
if(num>0){ // check out
System.out.println("Thread [" + Thread.currentThread().getId() +
"] is about to check out resources of: " + num);
pool.checkOut(num);
}else{ // check in
num = -num;
System.out.println("Thread [" + Thread.currentThread().getId() +
"] is about to check in resources of: " + num);
pool.checkIn(num);
}
}
public static void main(String[] args)
{
// initialize the resource pool
ResourcePool pool = new ResourcePool(2);
System.out.println("The pool starts with size of: " + pool.size());
// 5 threads to check out resuorce from the pool
ResourcePoolTester t1 = new ResourcePoolTester(pool, 1);
ResourcePoolTester t2 = new ResourcePoolTester(pool, 2);
ResourcePoolTester t3 = new ResourcePoolTester(pool, 3);
ResourcePoolTester t4 = new ResourcePoolTester(pool, 4);
ResourcePoolTester t5 = new ResourcePoolTester(pool, 5);
t1.start(); // returns immediately
t2.start(); // going to wait
t3.start(); // going to wait
t4.start(); // going to wait
t5.start(); // going to wait
// 2 threads to check in resource into the pool
ResourcePoolTester t6 = new ResourcePoolTester(pool, -6);
t6.start();
try{
Thread.sleep(1000); // just a second
}catch(Exception e){
}
ResourcePoolTester t7 = new ResourcePoolTester(pool, -9);
t7.start();
try{
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
t6.join();
t7.join();
}catch(Exception e){
}
System.out.println("The pool ends up with size of: " + pool.size());
}
}
class ResourcePool
{
/**
* the count monitoring how many resource currently reside in the pool
*/
private int count;
public ResourcePool(int count){
this.count = count;
}
public synchronized void checkOut(int num)
{
// check to see if there are enough resources?
while(count<num){
System.out.println("Thread [" + Thread.currentThread().getId() +
"] is waiting with pool size = " + size());
try{
wait(); // wait until there are enough resources
}catch(Exception e){
}
System.out.println("Thread [" + Thread.currentThread().getId() +
"] wakes up with pool size = " + size());
}
count -= num; // check-out
System.out.println("Thread [" + Thread.currentThread().getId() +
"] returns with pool size = " + size());
}
public synchronized void checkIn(int num)
{
count += num; // check-in
notifyAll();
System.out.println("Thread [" + Thread.currentThread().getId() +
"] checked in with pool size = " + size());
}
public synchronized int size(){
return count;
}
}
Here are the outputs:
The pool starts with size of: 2 Thread [7] is about to check out resources of: 1 Thread [7] returns with pool size = 1 Thread [8] is about to check out resources of: 2 Thread [8] is waiting with pool size = 1 Thread [9] is about to check out resources of: 3 Thread [9] is waiting with pool size = 1 Thread [10] is about to check out resources of: 4 Thread [10] is waiting with pool size = 1 Thread [11] is about to check out resources of: 5 Thread [11] is waiting with pool size = 1 Thread [12] is about to check in resources of: 6 Thread [12] checked in with pool size = 7 Thread [8] wakes up with pool size = 7 Thread [8] returns with pool size = 5 Thread [9] wakes up with pool size = 5 Thread [9] returns with pool size = 2 Thread [10] wakes up with pool size = 2 Thread [10] is waiting with pool size = 2 Thread [11] wakes up with pool size = 2 Thread [11] is waiting with pool size = 2 Thread [13] is about to check in resources of: 9 Thread [13] checked in with pool size = 11 Thread [10] wakes up with pool size = 11 Thread [10] returns with pool size = 7 Thread [11] wakes up with pool size = 7 Thread [11] returns with pool size = 2 The pool ends up with size of: 2
Observations: t1-Thread[7] checks out resource immediately since there are enough (2) resources for what it is asking (1); t2-Thread[8] ~ t5-Thread[11] have to wait until more resources are available; after t6-Thread[12] checks in 6 resources, its notification gets all waiting threads: t2-Thread[8], t3-Thread[9] , t4-Thread[10] and t5-Thread[11] to wake up. Among them, t2-Thread[8] and t3-Thread[9] return, but t4-Thread[10] and t5-Thread[11] have to continue waiting until available; again, t7-Thread[13]'s check-in notifyAll() and gets all the restl waiting threads: t4-Thread[10] and t5-Thread[11] to wake up and return; all threads have the fair chance to wake up the check their own status to see what to do next.
|
|
|
|
|
|
|
|