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);
    }
}

TaskUtil多线程与定时任务的更多相关文章

  1. spring多线程与定时任务

    本篇主要描述一下spring的多线程的使用与定时任务的使用. 1.spring多线程任务的使用 spring通过任务执行器TaskExecutor来实现多线程与并发编程.通常使用ThreadPoolT ...

  2. Java多线程之定时任务(Timer)

    package org.study2.javabase.ThreadsDemo.schedule; import java.util.Date; import java.util.Timer; imp ...

  3. spring的@Scheduled定时任务,同一时间段的定时任务只会执行一个,其余的会被阻塞,@Scheduled注解定时任务并发执行解决办法,即多线程运行定时任务

    原文:https://blog.csdn.net/qq_35937303/article/details/88851064 现有两个定时任务 @Component("aa") pu ...

  4. Spring Boot 定时任务单线程和多线程

    Spring Boot 的定时任务: 第一种:把参数配置到.properties文件中: 代码: package com.accord.task; import java.text.SimpleDat ...

  5. Spring4.0编程式定时任务配置

    看过很多定时调度的配置,大多使用XML配置,觉得比较麻烦,也比较老套.这里介绍一种基于spring4.0注解编程式配置定时任务,简单清晰,使用方便.. 至于引入spring相关jar这里不多说,直接切 ...

  6. JAVA基础知识之多线程——线程组和未处理异常

    线程组 Java中的ThreadGroup类表示线程组,在创建新线程时,可以通过构造函数Thread(group...)来指定线程组. 线程组具有以下特征 如果没有显式指定线程组,则新线程属于默认线程 ...

  7. java多线程编程核心技术——第五章总结

    定时器Timer的使用 1.1方法schedule(TimerTask task, Date time)的测试 1.2方法schedule(TimerTask task, Date firstTime ...

  8. springBoot中使用定时任务

    简单示例 导入依赖 springBoot已经默认集成了定时任务的依赖,只需要引入基本的依赖就可以使用定时任务. <parent> <groupId>org.springfram ...

  9. Java编程的逻辑 (80) - 定时任务的那些坑

    ​本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http: ...

随机推荐

  1. PostQueuedCompletionStatus

    PostQueuedCompletionStatus函数,向每个工作者线程都发送—个特殊的完成数据包.该函数会指示每个线程都“立即结束并退出”.下面是PostQueuedCompletionStatu ...

  2. apt-get &dpkg

    apt-get是ubuntu常用的软件安装工具.他可以很easy的从互联网上下载软件安装包,并实现安装. apt-get比较常用的命令如下: apt-get install packagename   ...

  3. UI:MVC设计模式

    不是因为有些事情难以做到,我们才失去自信:而是因为我们失去了自信,有些事情才显得难以做到.自信的第一步就是去尝试.不是因为有希望才坚持,而是因为坚持才有了希望.坚持尝试,就有可能成功.加油! Xcod ...

  4. OSGI(面向Java的动态模型系统)

    基本简介编辑 OSGI服务平台提供在多种网络设备上无需重启的动态改变构造的功能.为了最小化耦合度和促使这些耦合度可管理,OSGi技术提供一种面向服务的架构,它能使这些组件动态地发现对方.OSGi联 O ...

  5. 全代码实现ios-1

    第一次接触ios开发时,就决定用代码开发,而不用ib.因为被ib的各种控件的联线弄得一头雾水,而且ib和storyboard变动太快了. 开始的时候真是麻烦,因为网上关于全代码开发的例子太少了,大多数 ...

  6. vim编码相关配置

    主要与三个参数有有关 fileencoding 缩写:fenc 保存文件时所用的编码 set fenc 查看当前文件的编码 set fenc=utf-8 可以将当前文件转换为utf-8编码 filee ...

  7. 【MongoDB】mongoimport and mongoexport of data (一)

    In the software development, we usually are faced with a common question of exporting or importing d ...

  8. Ubuntu下很给力的下载工具

    Windows下的下载工具--迅雷,之所下面载速度快,乃是它能搜索资源.为己所用,而不是只从原始地址这单一资源处下载. Ubuntu下也有类似的工具,那就是aira2. aira2是一个命令行下载工具 ...

  9. Nmap 源代码学习四 软件简单使用

    软件安装环境是win7.使用Zenmap, nmap6.49BETA2 扫描主机port nmap -T4 -A -v 192.168.0.207 输出结果: 扫描整个子网 nmap 192.168. ...

  10. ORA-01489: result of string concatenation is too long

    ORA-01489: result of string concatenation is too long Cause: String concatenation result is more tha ...