//: concurrency/waxomatic2/WaxOMatic2.java
// Using Lock and Condition objects.
package concurrency.waxomatic2;
import static java.lang.System.out;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Car
{
//car has a lock, which is used when
//1) you are waxing the car
//2) the wax on the care disappear
//And obviously, these operations are exclusive to each other.
//
//Another very important thing about Lock object is:
//Pay attention to the format of lock()/unlock() usage as below:
//
//lock.lock()
//try
//{
// ... ...
//}
//finally
//{
//lock.unlock();
//}
private Lock lock = new ReentrantLock();
//in java1.4 and previous, we just wait() and notify()/notifyAll() on some object, generally "this"
//But in java1.5 concurrency, we will create a condition object, derived from Lock object.
//And all the await() and signal()/signalAll() are on this condition object.
private Condition condition = lock.newCondition();
private boolean waxOn = false;
/**
* you are waxing the car
*/
public void waxed()
{
lock.lock();
try
{
//-----location (1) where waitForWaxing() should be moved.
waxOn = true; // Ready to buff
condition.signalAll();
}
finally
{
lock.unlock();
}
}
/**
* the wax on the car disappeared
*/
public void buffed()
{
lock.lock();
try
{
//------location (2) where waitForBuffing() should be moved.
waxOn = false; // Ready for another coat of wax
condition.signalAll();
}
finally
{
lock.unlock();
}
}
/**
* I think this method is redundant. Because the 1st step if you want to wax a car, you need to wait for waxing.
* What I mean is, the condition.await() wrapped with while loop should be moved to location (1) of waxed() method.
* @throws InterruptedException
*/
public void waitForWaxing() throws InterruptedException
{
lock.lock();
try
{
while (waxOn == false) //wait must be surrended by while(condition)! Don't forget this!!
condition.await();
}
finally
{
lock.unlock();
}
}
/**
* quite similiar to the above method, should be moved to buffed() of location (2)
* @throws InterruptedException
*/
public void waitForBuffing() throws InterruptedException
{
lock.lock();
try
{
while (waxOn == true) //wait must be surrended by while(condition)! Don't forget this!!
condition.await();
}
finally
{
lock.unlock();
}
}
}
class WaxOn implements Runnable
{
private Car car;
public WaxOn(Car c)
{
car = c;
}
public void run()
{
try
{
while (!Thread.interrupted())
{
out.println("Wax On! ");
TimeUnit.MILLISECONDS.sleep(200);
car.waxed();
car.waitForBuffing();
}
}
catch (InterruptedException e)
{
out.print("Exiting via interrupt");
}
out.print("Ending Wax On task");
}
}
class WaxOff implements Runnable
{
private Car car;
public WaxOff(Car c)