定時任務工具類

/**
 * 定時任務
 * 
 * @author  <a href="mailto:biezhi.me@gmail.com" target="_blank">biezhi</a>
 * @since   1.0
 */
public abstract class TaskKit {
 
    private static Logger logger = Logger.getLogger(TaskKit.class);
 
    private static ScheduledThreadPoolExecutor taskScheduler = new ScheduledThreadPoolExecutor(getBestPoolSize());
    private static List<Timer> timerList = new ArrayList<Timer>();
 
    /**
     * 當即啓動,並以固定的頻率來運行任務。後續任務的啓動時間不受前次任務延時影響。
     * @param task 具體待執行的任務
     * @param period 每次執行任務的間隔時間(單位秒)
     */
    public static ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long periodSeconds) {
        return scheduleAtFixedRate(task, 0, periodSeconds, TimeUnit.SECONDS);
    }
 
    /**
     * 在指定的延時以後開始以固定的頻率來運行任務。後續任務的啓動時間不受前次任務延時影響。
     * @param task 具體待執行的任務
     * @param initialDelay 首次執行任務的延時時間
     * @param periodSeconds 每次執行任務的間隔時間(單位秒)
     * @param unit 時間單位
     */
    public static ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long initialDelay, long period, TimeUnit unit) {
        return taskScheduler.scheduleAtFixedRate(task, initialDelay, period, unit);
    }
 
    /**
     * 在指定的時間點開始以固定的頻率運行任務。後續任務的啓動時間不受前次任務延時影響。
     * @param task 具體待執行的任務
     * @param startTime 首次運行的時間點,支持 "yyyy-MM-dd HH:mm:ss" 格式
     * @param period 每次執行任務的間隔時間
     * @param unit 時間單位
     */
    public static void scheduleAtFixedRate(Runnable task, String startTime, long period, TimeUnit unit) throws ParseException {
        Date dt = DateKit.dateFormat(startTime, "yyyy-MM-dd HH:mm:ss");
        scheduleAtFixedRate(task, dt, period, unit);
    }
 
    /**
     * 在指定的時間點開始以固定的頻率運行任務。後續任務的啓動時間不受前次任務延時影響。
     * @param task 具體待執行的任務
     * @param startTime 首次運行的時間點
     * @param period 每次執行任務的間隔時間
     * @param unit 時間單位
     */
    public static void scheduleAtFixedRate(final Runnable task, Date startTime, final long period, final TimeUnit unit) {
        final Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                taskScheduler.scheduleAtFixedRate(task, 0, period, unit);
                timer.cancel();
                timerList.remove(timer);
            }
        }, startTime);
        timerList.add(timer);
    }
 
    /**
     * 當即啓動,兩次任務間保持固定的時間間隔
     * @param task 具體待執行的任務
     * @param period 兩次任務的間隔時間(單位秒)
     */
    public static ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long periodSeconds) {
        return scheduleWithFixedDelay(task, 0, periodSeconds, TimeUnit.SECONDS);
    }
 
    /**
     * 在指定的延時以後啓動,兩次任務間保持固定的時間間隔
     * @param task 具體待執行的任務
     * @param initialDelay 首次執行任務的延時時間
     * @param period 兩次任務的間隔時間(單位秒)
     * @param unit 時間單位
     */
    public static ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long initialDelay, long period, TimeUnit unit) {
        return taskScheduler.scheduleWithFixedDelay(task, initialDelay, period, unit);
    }
 
    /**
     * 在指定的時間點啓動,兩次任務間保持固定的時間間隔
     * @param task 具體待執行的任務
     * @param startTime 首次運行的時間點,支持 "yyyy-MM-dd HH:mm:ss" 格式
     * @param period 兩次任務的間隔時間
     * @param unit 時間單位
     */
    public static void scheduleWithFixedDelay(Runnable task, String startTime, long period, TimeUnit unit) throws ParseException {
        Date dt = DateKit.dateFormat(startTime, "yyyy-MM-dd HH:mm:ss");
        scheduleWithFixedDelay(task, dt, period, unit);
    }
 
    /**
     * 在指定的時間點啓動,兩次任務間保持固定的時間間隔
     * @param task 具體待執行的任務
     * @param startTime 首次運行的時間點
     * @param period 兩次任務的間隔時間
     * @param unit 時間單位
     */
    public static void scheduleWithFixedDelay(final Runnable task, Date startTime, final long period, final TimeUnit unit) {
        final Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                taskScheduler.scheduleWithFixedDelay(task, 0, period, unit);
                timer.cancel();
                timerList.remove(timer);
            }
        }, startTime);
        timerList.add(timer);
    }
 
    /**
     * 調整線程池大小
     * @param threadPoolSize
     */
    public static void resizeThreadPool(int threadPoolSize) {
        taskScheduler.setCorePoolSize(threadPoolSize);
    }
 
    /**
     * 返回定時任務線程池,可作更高級的應用
     * @return
     */
    public static ScheduledThreadPoolExecutor getTaskScheduler() {
        return taskScheduler;
    }
 
    /**
     * 關閉定時任務服務
     * <p>系統關閉時可調用此方法終止正在執行的定時任務,一旦關閉後不容許再向線程池中添加任務,不然會報RejectedExecutionException異常</p>
     */
    public static void depose() {
        int timerNum = timerList.size();
        //清除Timer
        synchronized (timerList) {
            for (Timer t: timerList)
                t.cancel();
            timerList.clear();
        }
         
        List<Runnable> awaitingExecution = taskScheduler.shutdownNow();
        logger.info("Tasks stopping. Tasks awaiting execution: %d", timerNum + awaitingExecution.size());
    }
 
    /**
     * 重啓動定時任務服務
     */
    public static void reset() {
        depose();
        taskScheduler = new ScheduledThreadPoolExecutor(getBestPoolSize());
    }
 
    /**
     * 根據 Java 虛擬機可用處理器數目返回最佳的線程數。<br>
     * 最佳的線程數 = CPU可用核心數 / (1 - 阻塞係數),其中阻塞係數這裏設爲0.9
     */
    private static int getBestPoolSize() {
        try {
            // JVM可用處理器的個數
            final int cores = Runtime.getRuntime().availableProcessors();
            // 最佳的線程數 = CPU可用核心數 / (1 - 阻塞係數)
            // TODO 阻塞係數是否是須要有個setter方法能讓使用者自由設置呢?
            return (int)(cores / (1 - 0.9));
        }
        catch (Throwable e) {
            // 異常發生時姑且返回10個任務線程池
            return 10;
        }
    }
}
相關文章
相關標籤/搜索