最近在开发blog的注册系统的时候遇到一个小小的困难,因为blog的注册是通过访问blog系统的页面并模拟人的行为来为用户注册的,在正常情况下是没有问题的,但是如果遇到异常,这样的注册方式就显得很脆弱了,比如用户已经注册过,这个时候虽然页面上会出现错误提示,但是用程序来捕捉这样的提示比较困难,而且如果这样做还需要加上更多的判断,考虑各种可能的异常情况,如果考虑不全,会极大降低该模块的可靠度。考虑再三之后,索性我就不去考虑有哪些异常情况了,全部统一处理,规定在一定时间内,这个注册blog的行为不能完成就认为是注册失败。
处理方案是有了,那该怎么实现这样的功能呢?在网上查阅了许多资料之后,找到了有个叫做守护线程的东西,觉得用它来完成这样的需求倒是挺方便的,所以在这里分享给大家。
首先,守护线程类如下:
/**
* 本线程设置了一个超时时间
* 该线程开始运行后,经过指定超时时间,
* 该线程会抛出一个未检查异常通知调用该线程的程序超时
* 在超时结束前可以调用该类的cancel方法取消计时
*/
public class TimeoutThread extends Thread{
/**
* 计时器超时时间
*/
private long timeout;
/**
* 计时是否被取消
*/
private boolean isCanceled = false;
/**
* 当计时器超时时抛出的异常
*/
private TimeoutException timeoutException;
/**
* 构造器
*
* @param timeout
* 指定超时的时间
*/
public TimeoutThread(long timeout, TimeoutException timeoutErr) {
super();
this.timeout = timeout;
this.timeoutException = timeoutErr;
// 设置本线程为守护线程
this.setDaemon(true);
}
/**
* 取消计时
*/
public synchronized void cancel() {
isCanceled = true;
}
/**
* 启动超时计时器
*/
public void run() {
try {
Thread.sleep(timeout);
if (!isCanceled)
throw timeoutException;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
下面定义要在TimeoutThread中抛出的异常,这个异常是关键,因为我们完全依靠捕捉这个异常才能知道我们需要执行的任务是否超时了,而且这个异常还有一个特殊之处在于,它不继承自Exception,而是继承自RuntimeException,这是为什么呢?原因是run方法重写了Thread中的run()方法,该方法不能抛出已检测的异常:
public class TimeoutException extends RuntimeException {
/**
* serialVersionUID
*/
private static final long serialVersionUID = 5961292480921511543L;
public TimeoutException(String errMessage){
super(errMessage);
}
}
现在万事具备,工具已经做好了,就差在需要的地方使用了,这种方式使用起来也是特别简洁明了,使用方法如下:
TimeoutThread t = new TimeoutThread(5000,new TimeoutException(”超时”));
try{
t.start();
//需要计时的任务
webAction();
t.cancel();
}catch(TimeoutException e){
//对超时的处理
throw new AreadyRegedException(”用户可能已经注册了blog,或访问blog系统时发生异常,请检查!”);
}