这篇文章我们来写一个小例子,充分利用notifyAll与wait等方法,来完成一个模拟游戏中不停的 “积累能量---放大招” 的例子!
我们先看运行结果,再看代码:
***********************************************************************************************
开始第1次积累能量
第1次积累能量完毕!
开始第1次使用能量释放大招
第1次使用能量释放大招完毕!
开始第2次积累能量
第2次积累能量完毕!
开始第2次使用能量释放大招
第2次使用能量释放大招完毕!
开始第3次积累能量
第3次积累能量完毕!
开始第3次使用能量释放大招
第3次使用能量释放大招完毕!
开始第4次积累能量
第4次积累能量完毕!
开始第4次使用能量释放大招
第4次使用能量释放大招完毕!
开始第5次积累能量
第5次积累能量完毕!
开始第5次使用能量释放大招
第5次使用能量释放大招完毕!
***********************************************************************************************
//游戏人物
class Role{
//能量是否积累完毕,这是一个信号量
private boolean energyed = false;
private int count = 0;
//开始积累能量
public void energyOn(){
while(!Thread.currentThread().isInterrupted()){
synchronized (this) {
try {
//一直检查能量状态,如果当前没有能量,则先积累能量完毕,再暂停自己并唤醒放大招的线程
while(!energyed){
//1.5秒才能积累完毕
System.out.println("开始第"+ (++count) +"次积累能量");
TimeUnit.MILLISECONDS.sleep(1500);
energyed = true;
System.out.println("第"+ count +"次积累能量完毕!");
notifyAll();
wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//使用能量
public void energyUse(){
while(!Thread.currentThread().isInterrupted()){
synchronized(this) {
try {
//一直检查能量状态,如果当前有能量,则放大招后再暂停自己且唤醒积累能量的线程
while(energyed){
System.out.println("开始第"+count+"次使用能量释放大招");
energyed = false;
System.out.println("第"+count+"次使用能量释放大招完毕!");
notifyAll();
wait();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
//一个简单的协作,全面演示wait,notify;所有的协作基本都是由一个信号量来进行流程控制的
public static void teamwork(){
//场景:你是个游戏人物,你在放大招之前需要等待积累能力...能力积累完后你立马放大招...放完又等待积累能力...周而复始
ExecutorService exec = Executors.newCachedThreadPool();
final Role role = new Role();
//执行使用能量释放大招线程
exec.execute(new Runnable() {
public void run() {
role.energyUse();
}
});
//执行积累能量线程
exec.execute(new Runnable() {
public void run() {
role.energyOn();
}
});
}
如代码中所示,我们来分解一下执行顺序:
1> role的energyOn()方法不断的积累能量,前提是它发现当前已经没有能量了;
2> 当它积累完能量后,它先唤醒等待此对象锁的线程然后自己进入等待状态;
3> 当它进入等待状态后,将释放对象锁,由此,等待使用能量的线程获得了执行机会;
4> 等待使用能量的线程先判断是否有能量可用,如果有,它开始消耗能量;
5> 消耗完能量后,它先唤醒等待此对象锁的线程然后自己进入等待状态;
6> 积累能量的线程被唤醒.........
稍微提一下,我们在while循环中的判断条件是当前线程没有被中断,我们可以调用Thread.interrupted()来打断当前线程的执行;
OK,这个协作就讲到这里,下一篇我们再来看看比较经典的 消费者与生产者模式;