package com.taoban.util;
/**
* 执行单次任务或定时任务工具类(用于减少new Thread()和new Timer()的使用)
*/
public class TaskUtil {
private static Log log = LogFactory.getLog(TaskUtil.class);
private static ExecutorService cachedExecutor = null;
private static ScheduledExecutorService scheduledExecutor = null;
private static Map<Runnable, Future<?>> keepRunningTasks = null;
private static Map<Future<?>, Callback> callbackdTasks = null;
static {
cachedExecutor = Executors.newCachedThreadPool(new TaskUtilThreadFactory("cached"));
scheduledExecutor = Executors.newScheduledThreadPool(5, new TaskUtilThreadFactory("scheduled"));
Runtime.getRuntime().addShutdownHook(new Thread() {//线程池自动退出
@Override
public void run() {
cachedExecutor.shutdown();
scheduledExecutor.shutdown();
log.info("TaskUtil executors shutdown.");
}
});
}
/**
* 立即执行任务
*/
public static Future<?> submit(Runnable task) {
return cachedExecutor.submit(task);
}
/**
* 自动保持任务持续运行,每分钟监视一次
*/
public static Future<?> submitKeepRunning(Runnable task){
Future<?> future = submit(task);
checkInitCachedTasks();
synchronized (keepRunningTasks) {
keepRunningTasks.put(task, future);
}
return future;
}
/**
* 延迟执行任务,例如延迟5秒:schedule(task,5,TimeUnit.SECONDS)
*/
public static void schedule(Runnable task, long delay, TimeUnit unit) {
scheduledExecutor.schedule(task, delay, unit);
}
/**
* 定时执行任务一次,比如下午两点:scheduleAt(task, DateUtils.setHours(new Date(), 13))
*/
public static void scheduleAt(Runnable task, Date time) {
long mills = time.getTime() - System.currentTimeMillis();
scheduledExecutor.schedule(task, mills>0 ? mills : 3, TimeUnit.MILLISECONDS);
}
/**
* 定时重复执行任务,比如延迟5秒,每10分钟执行一次:scheduleAtFixRate(task, 5, TimeUnit.MINUTES.toSeconds(10), TimeUnit.SECONDS)
*/
public static void scheduleAtFixtRate(Runnable task, long initialDelay, long delay, TimeUnit unit) {
scheduledExecutor.scheduleWithFixedDelay(task, initialDelay, delay, unit);
}
/**
* 定时重复执行任务,比如下午两点开始,每小时执行一次:scheduleAtFixRate(task, DateUtils.setHours(new Date(), 13), 1, TimeUnit.HOURS)
*/
public static void scheduleAtFixtRate(Runnable task, Date time, long delay, TimeUnit unit) {
long mills = time.getTime() - System.currentTimeMillis();
scheduledExecutor.scheduleWithFixedDelay(task, mills>0 ? mills : 3, unit.toMillis(delay), TimeUnit.MILLISECONDS);
}
/**
* 提交带返回值的任务,支持后续处理(调用者手动处理)
*/
public static <T> Future<T> submit(Callable<T> task) {
return cachedExecutor.submit(task);
}
/**
* 提交带返回值的任务,支持后续处理(自动调用Callback接口)
*/
public static <T> Future<T> submit(Callable<T> task, Callback callback) {
Future<T> future = submit(task);
checkInitCachedTasks();
if(callback != null) {
synchronized (callbackdTasks) {
callbackdTasks.put(future, callback);
}
}
return future;
}
/**
* 提交任务,等待返回值(阻塞调用者)
*/
public static <T> T wait(Callable<T> task) {
Future<T> future = cachedExecutor.submit(task);
try {
return future.get();
} catch (Exception e) {
log.warn(e);
return null;
}
}
private static void checkInitCachedTasks() {
if(keepRunningTasks != null) return;
keepRunningTasks = new HashMap<Runnable, Future<?>>();
callbackdTasks = new HashMap<Future<?>, Callback>();
scheduleAtFixtRate(new CachedTasksMonitor(), 1, 1, TimeUnit.MINUTES);
}
/**
* 监视需要保持运行的任务
*/
static class CachedTasksMonitor implements Runnable {
@Override
public void run() {
if(keepRunningTasks.size() > 0) {
synchronized (keepRunningTasks) {
Map<Runnable, Future<?>> tempTasks = null;
for(Runnable task : keepRunningTasks.keySet()) {
Future<?> future = keepRunningTasks.get(task);
if(future.isDone()) {
future = submit(task);//恢复运行异常结束任务
if(tempTasks == null) tempTasks = new HashMap<Runnable, Future<?>>();
tempTasks.put(task, future);
}
}
if(tempTasks != null && tempTasks.size() > 0) keepRunningTasks.putAll(tempTasks);
}
}
if(callbackdTasks.size() > 0) {
synchronized (callbackdTasks) {
List<Future<?>> callbackedFutures = null;
for(Future<?> future : callbackdTasks.keySet()) {
final Callback callback = callbackdTasks.get(future);
if(future.isDone()) {
try{
final Object result = future.get(5, TimeUnit.SECONDS);
submit(new Runnable() {
@Override
public void run() {//callback可能耗时所以作为独立运行任务,而本监视器需尽快完成工作
callback.handle(result);
}
});
if(callbackedFutures == null) callbackedFutures = new LinkedList<Future<?>>();
callbackedFutures.add(future);
}catch (Exception e) {
log.warn("TaskUtil callbackedTasks warn: ", e);
}
}
}
if(callbackedFutures != null && callbackedFutures.size() > 0) {
for(Future<?> future : callbackedFutures) {
callbackdTasks.remove(future);
}
}
}
}
}
}
/**
* 自定义线程名称Task-idx-name-idx2
*/
static class TaskUtilThreadFactory implements ThreadFactory {
private final static AtomicInteger taskutilThreadNumber = new AtomicInteger(1);
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String threadNamePrefix;
TaskUtilThreadFactory(String threadNamePrefix){
this.threadNamePrefix = threadNamePrefix;
}
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, String.format("TaskUtil-%d-%s-%d", taskutilThreadNumber.getAndIncrement(), this.threadNamePrefix, threadNumber.getAndIncrement()));
t.setDaemon(false);
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
/**
* 等待结果回调接口
*/
public static interface Callback {
void handle(Object result);
}
}
- spring多线程与定时任务
本篇主要描述一下spring的多线程的使用与定时任务的使用. 1.spring多线程任务的使用 spring通过任务执行器TaskExecutor来实现多线程与并发编程.通常使用ThreadPoolT ...
- Java多线程之定时任务(Timer)
package org.study2.javabase.ThreadsDemo.schedule; import java.util.Date; import java.util.Timer; imp ...
- spring的@Scheduled定时任务,同一时间段的定时任务只会执行一个,其余的会被阻塞,@Scheduled注解定时任务并发执行解决办法,即多线程运行定时任务
原文:https://blog.csdn.net/qq_35937303/article/details/88851064 现有两个定时任务 @Component("aa") pu ...
- Spring Boot 定时任务单线程和多线程
Spring Boot 的定时任务: 第一种:把参数配置到.properties文件中: 代码: package com.accord.task; import java.text.SimpleDat ...
- Spring4.0编程式定时任务配置
看过很多定时调度的配置,大多使用XML配置,觉得比较麻烦,也比较老套.这里介绍一种基于spring4.0注解编程式配置定时任务,简单清晰,使用方便.. 至于引入spring相关jar这里不多说,直接切 ...
- JAVA基础知识之多线程——线程组和未处理异常
线程组 Java中的ThreadGroup类表示线程组,在创建新线程时,可以通过构造函数Thread(group...)来指定线程组. 线程组具有以下特征 如果没有显式指定线程组,则新线程属于默认线程 ...
- java多线程编程核心技术——第五章总结
定时器Timer的使用 1.1方法schedule(TimerTask task, Date time)的测试 1.2方法schedule(TimerTask task, Date firstTime ...
- springBoot中使用定时任务
简单示例 导入依赖 springBoot已经默认集成了定时任务的依赖,只需要引入基本的依赖就可以使用定时任务. <parent> <groupId>org.springfram ...
- Java编程的逻辑 (80) - 定时任务的那些坑
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http: ...
随机推荐
- 编译安装-MySQL5.5
一.参数选项 1.目录选项 2.存储引擎选项 3.库文件加载选项 二.安装 1.环境准备 2.安装前的系统设置 3.安装执行 4.初始化数据库 5.注册为服务 6.加入环境变量 7.启动服务 8.重新 ...
- 给js function的参数设置默认值
C# 中 function func(a,b=1){//具体方法} js 中 function func(a,b){ a= arguments[0] || 10; b= arguments[1] || ...
- 一个可创建读取日志的管理类(可固定创建2M大小的日志文件)
这里,将日志管理基类命名为LogManagerBase(抽象类),具体的不同类型的日志可以通过继承完成.该基类可将日志以每个2M的方式存储起来,并可以读取当前正在使用的日志的所有内容. 要实现该基类, ...
- 移动端类似IOS的滚动年月控件(需要jQuery和iScroll)
一. 效果图 二. 功能介绍 支持滚动和点击选择年月.(目前只支持设置年月的最大最小值,不支持整体的最大最小值) 三. 代码 1. 在你的html中添加如下代码: 直接加载<body>里面 ...
- erlang启动参数
出自: http://blog.sina.com.cn/s/blog_96b8a154010123cc.html
- svn的搭建
http://www.cnblogs.com/xiaobaihome/archive/2012/03/20/2407610.html
- PHP 打印调用函数入口地址(堆栈),方便调式
今天网站出现一个BUG,然后直接在数据库类里面写日志,看是哪条SQL出了问题,SQL语句到是找到了,但是不知道这条SQL语句来自何处,于是就想啊,如果能有一个办法,查看当前正在运行的这个方法是被哪个方 ...
- Windows Server Backup 2008 R2 备份Hyper-V
要备份 Hyper-V 虚拟机从父分区在 Windows Server 2008 上使用 Windows 服务器备份,您必须注册 Microsoft Hyper-V VSS 编写器 Windows 服 ...
- YOUYOU深入学习Ganglia之三(gmetad的软件架构)
Ganglia这个东西,目前的情况是测试的多,真正在数据中心部署过的人少:使用的多,真正能了解其代码架构的人少.这里根据我的经验,分解一下ganglia的gmetad的软件架构,欢迎大家交流. 上面的 ...
- Swift学习笔记十二
方法 方法就是和某种特定类型相关联的函数.类.结构体.枚举都可以定义实例方法和类型方法.类型方法和OC中的类方法类似. 结构体和枚举也可以定义方法是Swift与C/OC之间很大的一个区别,在OC中,只 ...