1. Car类
class Car {
//Car有一个单一的布尔属性waxOn ,表示涂蜡•抛光处理的状态。
//初始是可以打蜡的状态
private boolean waxOn = false;
public synchronized void notifyBuffer() {
waxOn = true; // Ready to buff 可以抛光
notifyAll();
}
public synchronized void notifyWax() {
waxOn = false; // Ready for another coat of wax 可以打蜡
notifyAll();
}
//等待打蜡 挂起抛光线程
public synchronized void haltBuffer()
throws InterruptedException {
//一直循环检查 只要是可以打蜡的状态就挂起抛光的线程
while (waxOn == false)
wait();
}
//等待抛光 挂起打蜡线程
public synchronized void haltWax()
throws InterruptedException {
//一直循环检查 只要是可以抛光的状态就挂起打蜡的线程
while (waxOn == true)
wait();
}
}
2. WaxOn类
//打蜡
class WaxOn implements Runnable {
private volatile double d = 0.0;
Logger logger = LoggerFactory.getLogger(WaxOn.class);
private Car car;
public WaxOn(Car c) {
car = c;
}
public void run() {
try {
while (!Thread.interrupted()) {
//模拟打蜡 非阻塞
long start = System.currentTimeMillis();
for (int i = 1; i < 100000000; i++)
d = d + (Math.PI + Math.E) / d;
long end = System.currentTimeMillis();
logger.info(String.valueOf(end-start));
logger.info("Wax On! ");
//将waxOn = true 之后通知抛光线程
car.notifyBuffer();
//挂起打蜡的线程
car.haltWax();
}
} catch (InterruptedException e) {
logger.info("Exiting Wax on via interrupt");
}
logger.info("Ending Wax On task");
}
}
3. WaxOff类
//抛光
class WaxOff implements Runnable {
Logger logger = LoggerFactory.getLogger(WaxOff.class);
private Car car;
private volatile double d = 0.0;
public WaxOff(Car c) {
car = c;
}
public void run() {
try {
//使用了中断的惯用法
while (!Thread.interrupted()) {
//初始是可以打蜡的状态
//只要是可以打蜡状态 就将抛光线程挂起
//初始waxOn=off 挂起抛光线程
car.haltBuffer();
//模拟抛光 非阻塞耗时任务
long start = System.currentTimeMillis();
for (int i = 1; i < 100000000; i++)
d = d + (Math.PI + Math.E) / d;
long end = System.currentTimeMillis();
logger.info(String.valueOf(end-start));
logger.info("Wax Off! ");
//waxOn时获取 将其变为waxOff 之后notifyAll
car.notifyWax();
}
} catch (InterruptedException e) {
logger.info("Exiting Wax off via interrupt");
}
logger.info("Ending Wax Off task");
}
}
4. WaxOMatic类
public class WaxOMatic {
public static void main(String[] args) throws Exception {
Car car = new Car();
ExecutorService exec = Executors.newCachedThreadPool();
//这两个线程都有可能先启动执行
exec.execute(new WaxOff(car));
exec.execute(new WaxOn(car));
TimeUnit.MILLISECONDS.sleep(1200); // Run for a while...
//此时 对于WaxOn Thread 由于其线程挂起,那么直接catch InterruptedException
//对于WaxOff Thread,其正在执行非阻塞的数学计算 此时interrupt,
//首先循环将结束,然后循环会经由while语句的顶部退出
//使用了耗时任务来模拟
exec.shutdownNow(); // Interrupt all tasks
}
}
类图:
其时序图为
注意几点:
1. 其任务类中使用的while(!Thread.interrupted()){try{}catch{}}的惯用法,当程序处于wait()下的阻塞状态以及在while中非阻塞操作中这两种状态都可以响应外部中断。前者直接抛出InterruptedException异常,而后者会首先循环将结束,然后循环会经由while语句的顶部退出。
2. 其wait()及notifyAll()的顺序流弄清
首先启动两个线程,这两个线程的先后启动顺序是不确定的,但要最初就保证WaxOn先执行,所以WaxOff线程启动后先挂起线程。之后就是WaxOn WaxOff这两个线程在run方法中不断循环。之后就是在一个循环中修改状态,通知,挂起线程,交叉执行。
自己要能够看着类图把程序完整写出来。
使用BlockingQueue实现WaxOnWaxOff程序见:使用BlockingQueue实现WaxOnWaxOff程序