在java web中有些时候我们的任务并不都是统一的而有点像是定制的,即不确定的临时任务
场景说明:在调用其他平台的接口时,并不知道该平台是否突然运行异常缓慢导致我们的方法长时间停留此处无法返回以至于客户端一直停留在当前页面无任何反应出现假死的现象。
解决办法:判断当前的调用方法是否超过了我们预想的运行时长,出现了则停止该方法的运行并及时返回运行超时的状态,以便于启动任务在预定时间后再次调用该平台的方法执行一次,如此往复直到执行成功不再重建该定时任务为止
用到的相关java类:timeTask,Callable和Future
我们并不直接使用thread 线程(包括runable)主要出于性能,在就是java本身带有线程的类实现了我们要用到的场景方法;
Timer是jdk中提供的一个定时器工具,使用的时候会在主线程之外起一个单独的线程执行指定的计划任务,可以指定执行一次或者反复执行多次。
TimerTask是一个实现了Runnable接口的抽象类,代表一个可以被Timer执行的任务。
因此它动态的任务调度基本条件都具备了
以下段落出自原文地址:http://blog.csdn.net/ghsau/article/details/7451464
Callable接口类似于Runnable,从名字就可以看出来了,但是Runnable不会返回结果,并且无法抛出返回结果的异常,而Callable功能更强大一些,被线程执行后,可以返回值,这个返回值可以被Future拿到,也就是说,Future可以拿到异步执行任务的返回值
FutureTask实现了两个接口,Runnable和Future,所以它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值,那么这个组合的使用有什么好处呢?假设有一个很耗时的返回值需要计算,并且这个返回值不是立刻需要的话,那么就可以使用这个组合,用另一个线程去计算返回值,而当前线程在使用这个返回值之前可以做其它的操作,等到需要这个返回值时,再通过Future得到,岂不美哉!这里有一个Future模式的介绍:http://openhome.cc/Gossip/DesignPattern/FuturePattern.htm。
大概的知识讲到这里,基本也讲清楚了我们不直接使用thread的原因;回到正题,我的具体实现如下
timeTask的任务类
package com.halis.souhuo.webService.task;
import java.util.HashMap;
import java.util.Timer;
import java.util.TimerTask;
import org.springframework.beans.factory.annotation.Autowired;
import com.halis.core.cache.entity.SimpleConcurrentMap;
import com.halis.platform.entity.Goods;
import com.halis.souhuo.uc.model.LogService;
import com.halis.souhuo.webService.condition.TrackInfo;
import com.halis.souhuo.webService.model.SynchroDataService;
/**
* @projName:souhuow
* @className:SynTimerHandler
* @description:webservice调用超时后采用Timer定时的方式再次执行
* @creater:Administrator
* @creatTime:2015年11月22日 上午9:18:54
* @alter:zjcjava@163.com
* @alterTime:2015年11月22日 上午9:18:54
* @remark:
* @version
*/
public class SynTimerHandler {
private static final long SECOND_TIME =1000;//默认过期时间 1秒执行一次任务
private static final int DEFUALT_VALIDITY_TIME =60;//60*60*24*1;//默认过期时间 1分种*1小时*24*1天秒
private static final Timer timer ;
//public static final SimpleConcurrentMap<String, Object> tokenMap;
public static final SimpleConcurrentMap<String, Object> taskMap;///任务调度缓存
static{
timer = new Timer();
//tokenMap = new SimpleConcurrentMap<String, Object>(new HashMap<String, Object>(1<<18));
taskMap = new SimpleConcurrentMap<String, Object>(new HashMap<String, Object>(1<<18));
}
/**
* 增加缓存对象
* @param key
* @param ce
*/
public static void addTask(String key, Object ce,SynchroDataService synchroDataService){
addTask(key, ce,synchroDataService, DEFUALT_VALIDITY_TIME);
}
/**
* 增加任务对象
* @param key
* @param ce
* @param validityTime 有效时间
*/
public static synchronized void addTask(String key, Object ce,SynchroDataService synchroDataService, int validityTime){
//添加过期定时
SynDateTimerTask task= new SynDateTimerTask(key,ce,synchroDataService);
timer.schedule(task, validityTime * SECOND_TIME);
taskMap.put(key, task);///把该任务放入缓存中
}
/**
* 获取taskMap缓存对象
* @param key
* @return
*/
public static synchronized Object getTimerTask(String key){
return taskMap.get(key);
}
/**
* 检查taskMap是否含有制定key的缓冲
* @param key
* @return
*/
public static synchronized boolean isConcurrent(String key){
return taskMap.containsKey(key);
}
/**
* 删除taskMap缓存
* @param key
*/
public static synchronized void removeTimerTask(String key){
//tokenMap.remove(key);
taskMap.remove(key);///最后从缓存中删除任务缓存
}
/**
* 获取缓存大小
* @param key
*/
public static int getTimerTaskSize(){
return taskMap.size();
}
/**
* 清除全部缓存
*/
public static synchronized void clearTimerTask(){
if(null != timer){
timer.cancel();
}
taskMap.clear();
System.out.println("clear task");
}
}
timtask类
/**
* @projName:搜货网
* @className:synDateTimerTask
* @description:<p>定时任务服务类,key className_Id,Object entity</p>
*/
public class SynDateTimerTask extends TimerTask{
private String key ;
private Object obj ;
@Autowired
SynchroDataService synchroDataService;
public SynDateTimerTask(String key, Object obj,SynchroDataService synchroDataService){
this.key = key;
this.obj = obj;
this.synchroDataService=synchroDataService;
}
@Override
public void run() {
///同步数据
String [] type= key.split("_");
int res=0;
switch (type[0]) {
case "Goods":
res=synchroDataService.addGoods((Goods)obj);
break;
case "OrderTrack":
res=synchroDataService.addOrderTrack((TrackInfo)obj);
break;
default:
break;
}
if(res==2){///TMS运行超时添加到任务中
System.out.println("task false "+System.currentTimeMillis());
//addTask(key,obj);
}else{///其他状态则为数据问题不在添加到任务中
}
// int res=synchroDataService.addGoods(goods);
System.out.println("task runing : "+this.key);
}
}
///mian正常流程调用的方法,只贴了主要实现的部分,同时提一句,因为用的service是注解的,所以上面的线程中用到的service地方在这里是直接丢就去的
Executor executor=Executors.newSingleThreadExecutor();
FutureTask future=new FutureTask(new Callable() {//创建一个futuretask线程
public String call() throws Exception {
// TODO Auto-generated method stub
return NetUtils.changeTmsUrl("SyncOrder", arg);// /调用webservice,我这里调用的是webservice方法,根据你直接的实际情况改成其他的方法,call的方返回类型要和这个地方对应
}
});
executor.execute(future);
String res=null;///运行的结果
try{
res=future.get(5000, TimeUnit.MILLISECONDS).toString(); //取得结果,同时设置超时执行时间为5秒。同样可以用future.get(),不设置执行超时时间取得结果
System.out.println(res);
}catch (InterruptedException e) {
// TODO: handle exception
res="{\"flag\":false,\"code\":\"2001\",\"message\":\"方法执行中断\"}";
System.out.println("方法执行中断");
future.cancel(true);
}catch (ExecutionException e) {
res="{\"flag\":false,\"code\":\"2002\",\"message\":\"Excution异常\"}";
System.out.println("Excution异常");
// TODO: handle exception
future.cancel(true);
}catch (TimeoutException e) {
// TODO: handle exception
res="{\"flag\":false,\"code\":\"2004\",\"message\":\"Timeout佳捷平台运行超时\"}";
System.out.println("方法执行时间超时");
future.cancel(true);
}
StateMessage st=JSON.parseObject(res, StateMessage.class);//jsoN转对象
System.out.println("数据导入结果:"+res);
if(st.isFlag()){
state=0;
}else{
if(st.getMessage().contains("Timeout")){///TMS运行超时则进行任务处理
state=2;
}else{
state=-1;
}
}
switch (state) {
case 2:///TMS运行超时进行任务处理
SynTimerHandler.addTask("Goods_"+goods.getId(), goods,this);
break;
default:
//SynTimerHandler.removeTimerTask("Goods_"+goods.getId());//其他状态则默认删除,当然这里是不必要的
break;
}