背景
在java的场景中,往往会遇到定时执行一些任务的场景,我把解决方案分为基于spring技术栈的和原生java技术栈的,定时执行任务很容易实现,但是过程中,需要踩很多坑,比如定时任务阻塞,定时任务执行报异常,定时任务超时等等的运行时情况,需要让定时任务很好的兼容,不能宕机。
解决方案
定时任务,当需要跟外部资源交互的时候,比如发送socket请求,发送rpc请求,获得数据库链接等等的需要与外部资源交互的时候,一旦触发异常或者是超时,需要有处理策略,保证定时任务,正常运行才可以,不能因为出现异常就崩了,阻塞了,不执行了。
JAVA自身定时任务方案
实现起来,需要考虑两步,定时任务的执行机制 + 执行过程中的保障机制。 这里举一个超时的例子,保证出现超时异常,其他异常的时候,代码会照样执行,如果没有保障机制,线程就会阻塞,一旦阻塞,就不会二次执行了,定时的功能就失去了。
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(new Runnable() {
public void run() {
final ExecutorService exec = Executors.newFixedThreadPool(1);
Callable<String> call = new Callable<String>() {
public String call() throws Exception {
//开始执行耗时操作 把那个run方法的功能放进来
Thread.sleep(1000 * 5);
throw new TimeoutException();
//return "线程执行完成.";
}
};
try {
Future<String> future = exec.submit(call);
String obj = future.get(1000 * 4, TimeUnit.MILLISECONDS); //任务处理超时时间设为 4 秒
System.out.println("任务成功返回:" + obj);
} catch (TimeoutException ex) {
System.out.println("处理超时啦....");
ex.printStackTrace();
} catch (Exception e) {
System.out.println("处理失败.");
e.printStackTrace();
}finally {
// 关闭线程池
exec.shutdown();
}
}
}, 0, 4, TimeUnit.SECONDS);
// 阻塞线程,模拟主程序一直运行
try {
Thread.sleep(1000000000);
}catch (Exception e){
}
spring方案
spring封装的比较好了,只增加定时任务的执行保障机制就可以了。建议加异步标签,防止影响主线程。调用的方法内部自己根据业务加保障机制,比如超时,异常捕捉,等等
/**
*定时清除frame
*/
@Async
@Scheduled(initialDelay = 5*1000,fixedRate = 3000)
public void autoClearFrame() {
frameCache.autoClear();
}