package org.nutz.runner;
import java.util.Date;
import org.nutz.lang.Times;
import org.nutz.log.Log;
import org.nutz.log.Logs;
/**
* 所有后台运行的业务逻辑均需集成本类
*
* @author zozoh(zozohtnt@gmail.com)
* @author pw
*/
public abstract class NutRunner implements Runnable {
protected Log log;
protected Thread myThread;
/**
* 本运行器名称
*/
protected String rnm;
/**
* 线程锁
*/
protected NutLock lock;
/**
* 累积启动次数
*/
protected int count;
/**
* 本次睡眠时间
*/
protected long interval;
/**
* 启动于
*/
protected Date upAt;
/**
* 睡眠于,如果本值不为 null,表示本线程正在睡眠,否则为运行中
*/
protected Date downAt;
public NutRunner(String rname) {
this.rnm = rname;
this.count = 0;
this.lock = new NutLock();
}
public void run() {
if (log == null) {
log = Logs.get().setTag(rnm);
}
myThread = Thread.currentThread();
beforeStart(this);
doIt();
afterStop(this);
}
/**
* 具体的业务实现,返回一个sleep数
*
* @return 本次运行后还需要等待多少个毫秒
*/
public abstract long exec() throws Exception;
@Deprecated
public void reg(NutRunner me) {}
@Deprecated
public void unreg(NutRunner me) {};
/**
* 开始之前,一般做一些准备工作,比如资源初始化等
*
* @param me
* runner本身
*/
public void beforeStart(NutRunner me) {
reg(me);
};
/**
* 停止之后,一般是做一些资源回收
*
* @param me
* runner本身
*/
public void afterStop(NutRunner me) {
unreg(me);
}
/**
* 做一些需要定期执行的操作
*/
protected void doIt() {
while (!lock.isStop()) {
synchronized (lock) {
try {
// 修改一下本线程的时间
upAt = Times.now();
downAt = null;
log.debugf("%s [%d] : up", rnm, ++count);
// 执行业务
interval = exec();
if (interval < 1)
interval = 1; // 不能间隔0或者负数,会死线程的
// 等待一个周期
downAt = Times.now();
log.debugf("%s [%d] : wait %ds(%dms)", rnm, count, interval / 1000, interval);
lock.wait(interval);
}
catch (InterruptedException e) {
log.warn(String.format("%s has been interrupted", rnm), e);
break;
}
catch (Throwable e) {
log.warn(String.format("%s has some error", rnm), e);
try {
lock.wait(30 * 1000);
}
catch (Throwable e1) {
log.warn(String.format("%s has some error again", rnm), e);
break;
}
}
}
}
}
public String toString() {
return String.format("[%s:%d] %s/%s - %d",
rnm,
count,
upAt == null ? "NONE" : Times.sDT(upAt),
downAt == null ? "NONE" : Times.sDT(downAt),
interval);
}
public boolean isWaiting() {
return null != downAt;
}
public boolean isRunning() {
return null == downAt;
}
public long getInterval() {
return interval;
}
public Date getUpAt() {
return upAt;
}
public Date getDownAt() {
return downAt;
}
public String getName() {
return rnm;
}
public int getCount() {
return count;
}
public NutLock getLock() {
return lock;
}
public boolean isAlive() {
if (myThread != null) {
return myThread.isAlive();
}
return false;
}
@SuppressWarnings("deprecation")
public void stop(Throwable err) {
myThread.stop(err);
}
}