在责任链模式里谈到击鼓传花的游戏,想一想就会发现,击鼓的活动和传花的活动应当是两个独立的线程:击鼓线程
开始运行,代表游戏开始;传花的线程开始运行,代表传花的人们开始传花,击鼓结束表示时间到了,传花的活动便
立即停止,代表传花的线程则需要执行一项任务.
一:线程
线程是可以在一个程序里面平行运行的执行路线,线程与线程之间可以共享变量。 Java的线程启动很快,而且程序员
可以比控制进程更加容易控制线程,使用线程可以使程序快速地处理同时来自不同计算机的请求,因此在分散系统设
计里,常常要使用线程.
二:定时器
线程的编程比较不容易掌握,所以除非特别需要,应当尽量作用高级线程API。如java.util.Timer类便是1.3引入的
定时器类,此类封装了定时器所需要的线程功能。与此类相应的还有一个TimerTask类,封装了当被定时的任务需要
反复发生时所需要的线程功能。如果仅仅是为了定时执行一个操作,应当使用Timer类.Timer是TimerThread的子类,
而TimerThread是Thread的实现,因此Timer是Thread的实现,同时TimerTask是Runnable的实现,从而也是一个线程
,这就是说,Timer和TimerTask都是线程,而且彼此是独立的。请看:
package cai.milenfan.basic.test;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
public class MailTimer extends HttpServlet{
private static final Timer TIMER = new Timer();
private Timer timer;
public MailTimer(int seconds){
timer = new Timer();
timer.schedule(new RenindTask(), seconds*1000);
}
public void init() throws ServletException {
System.out.println("...............init");
Date date = new Date();
date.setHours(8);
date.setMinutes(10);
TIMER.schedule(new MailTimerTask(), date, 120000);
}
class RenindTask extends TimerTask{
public void run() {
System.out.println("......");
timer.cancel();
}
}
static class MailTimerTask extends TimerTask {
public void run() {
System.out.println(".........................run");
}
}
public static void main(String[] args){
new MailTimer(5);
}
}
在每一个Timer对象背后,都有一个背景线程,用来顺序执行Timer的任务,这些任务应当迅速结束,不然就会霸占
timer用来执行任务的线程,从而延迟后面的任务。当所有的任务都完成后,timer的任务执行线程就会顺利结束并被
Java垃圾收集器收集,只是垃圾收集的时间并不能预测,如果程序想要迅速地结束timer的任务执行线程,调用方就
应当调用timer的cancel()方法,如上面的例子.
Timer类是线程安全的,换言之,可以多个线程共享一个Timer对象,而不需要同步化,这就是使用Timer的一个好处.
应该注意的事,Timer实际上是用Object.wait(long)方法实现定时的,因此Timer类不能保证实时效果.
三:模拟红楼梦中的击鼓传花
击鼓传花的游戏其实应当用两个线程来描述,一个线程用于模拟击鼓,另一个线程用于模拟传花,击鼓过程只持续一
段时间,因此可以使用Timer来定时执行,击鼓停止对于所有参加传花的宾客而言是一个公共的信号,它意味着传花
立即停止,当传花停止时,手中拿着花的宾客就应执行酒令,然后重新开始。
package cai.milenfan.basic.test;
public abstract class Player {//抽象传花者
abstract public void handle();
private Player successor;//设定下家
public Player() {
successor = null;
}
protected void setSuccessor(Player aSuccessor) {
successor = aSuccessor;
}
public void next() {//向下家传花
if (successor != null) {
successor.handle();
} else {
System.out.println("Program terminated.");
}
}
}
package cai.milenfan.basic.test;
public class JiaMu extends Player {
public JiaMu(Player aSuccessor) {
this.setSuccessor(aSuccessor);
}
public void handle() {
if (DrumBeater.stopped) {
System.out.println("Jia Mu gotta drink!");
} else {
System.out.println("Jia Mu passed!");
next();
}
}
}
package cai.milenfan.basic.test;
public class JiaHuan extends Player {
public JiaHuan(Player aSuccessor) {
this.setSuccessor(aSuccessor);
}
public void handle() {
if (DrumBeater.stopped) {
System.out.println("Jia Huan gotta drink!");
} else {
System.out.println("Jia Huan passed!");
next();
}
}
}
package cai.milenfan.basic.test;
public class JiaBaoYu extends Player {
public JiaBaoYu(Player aSuccessor) {
this.setSuccessor(aSuccessor);
}
public void handle() {
if (DrumBeater.stopped) {
System.out.println("Jia Bao Yu gotta drink!");
} else {
System.out.println("Jia Bao Yu passed!");
next();
}
}
}
package cai.milenfan.basic.test;
import java.util.Timer;
import java.util.TimerTask;
public class DrumBeater {
private static Player firstPlayer;
public static boolean stopped = false;
Timer timer;
static public void main(String[] args) {
DrumBeater drumBeater = new DrumBeater();
JiaMu jiaMu = new JiaMu(null);
jiaMu.setSuccessor(new JiaShe(
new JiaZheng(new JiaBaoYu(new JiaHuan(jiaMu)))));//排成一个圈
drumBeater.startBeating(1);
firstPlayer = jiaMu;
firstPlayer.handle();
}
public void startBeating(int stopInSeconds) {
System.out.println("Drum beating started...");
timer = new Timer();
timer.schedule(new StopBeatingReminder(), stopInSeconds);
}
class StopBeatingReminder extends TimerTask {
public void run() {
System.out.println("Drum beating stopped!");
stopped = true;
timer.cancel(); // Terminate the timer thread
}
}
}