Java ScheduledThreadPoolExecutor 一个优于Timer、TimerTask的定时任务

时间:2021-06-29 00:13:40

最近因为工作的需要,要用到Java的定时任务,JDK1.5之前的Timer和TimerTask类已经过时了,

特地从网上找了一些材料汇总了以下,方便以后的学习。


//删除其中一个任务

http://www.iteye.com/problems/78147


http://zhidao.baidu.com/link?url=ZMRiUrVtBUbXLZIc1kgpTms7QrJAn-122-plrZFmoywmzAGHrYkTkgfLqaZZ-x2WQfA86x6bWIA2rnsnDmhtqoUAOFYTCW_SfGItsgcKjg_



http://bbs.csdn.net/topics/380145101


http://olylakers.iteye.com/blog/1218243


http://www.2cto.com/kf/201208/145943.html


以下是原文转载,转载自:http://hi.baidu.com/yanfei_nn/item/c73802014089319b03ce1b5f

Java 一个优于Timer的定时器——ScheduledThreadPoolExecutor

1. TimeUnit 时间单元

       换算进制:

1
2
3
4
5
6
7
static  final  long  C0 = 1L;  // 1微毫秒
static  final  long  C1 = C0 * 1000L;  // 1微秒=1000微毫秒
static  final  long  C2 = C1 * 1000L;  // 1毫秒=1000微秒
static  final  long  C3 = C2 * 1000L;  // 1秒=1000毫秒
static  final  long  C4 = C3 * 60L;  // 1分=60秒
static  final  long  C5 = C4 * 60L;  // 1时=60分
static  final  long  C6 = C5 * 24L;  // 1天=24时
 

       1) 可以快速实现时间格式转换
       toNanos、toMicros、toMillis、toSeconds、toMinutes、toHours、toDays

       2) 以指定格式快速实现线程停滞
       sleep
       TimeUnit.SECONDS.sleep(1); <=> Thread.sleep(1000) // 线程等待1秒

2. ScheduledThreadPoolExecutor

      1) ScheduledThreadPoolExecutor是在JDK1.5以后提供可以实现定时、重复运行任务的功能,类似Timer,优于Timer

      2) 构造方法

             a) ScheduledThreadPoolExecutor(int corePoolSize)使用给定核心池大小创建一个新 ScheduledThreadPoolExecutor

       b)ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactorythreadFactory)使用给定的初始参数创建一个新对象

b可以提供线程创建工厂

1
2
3
4
5
6
7
8
9
10
private  final  static  ScheduledThreadPoolExecutor schedual =  new  ScheduledThreadPoolExecutor( 1 , newThreadFactory() { 
            
     private  AtomicInteger atoInteger =  new  AtomicInteger( 0 ); 
            
     public  Thread newThread(Runnable r) { 
         Thread t =  new  Thread(r); 
         t.setName( "xxx-Thread " + atoInteger.getAndIncrement()); 
         returnt; 
    
});
 
 

      3) 调度方法

             a) schedule(Callable callable, long delay, TimeUnit unit); 延迟delay时间后开始执行callable

             b) scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit);  延迟initialDelay时间后开始执行command,并且按照period时间周期性重复调用,如果command运行时间较长、可能会同时执行(周期时间包括command运行时间)

             c) scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit); 延迟initialDelay时间后开始执行command,并且按照period时间周期性重复调用,并且保证在上次运行完后才会执行下一次(周期时间不包括command运行时间)

      4) 全局线程方法参数

             a) setContinueExistingPeriodicTasksAfterShutdownPolicy(boolean value) 如果value为true,则在主线程shutdown()方法后如果还没有执行(未达到delay的时间),则延迟任务仍然有机会执行,反之则不会执行,直接退出。(针对b、c方法)

             b) setExecuteExistingDelayedTasksAfterShutdownPolicy(boolean value) 如果value为true,则在主线程shutdown()方法后如果还没有执行(未达到delay的时间),则延迟任务仍然有机会执行,反之则不会执行,直接退出。(针对a方法)

3. ScheduledFuture 

        在执行调度之后返回该对象。它可以判断任务是否已经执行、是否已经取消、取消以后的操作

4. 操作实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/**
* 定时执行任务
* @author 闫海鹏
*/
public  class  TestTimer  implements  Runnable {
     
     public  static  void  main(String[] args) {
         new  TestTimer();
     }
     
     /**
      * 时间调度器
      */
     private  final  static  ScheduledThreadPoolExecutor schedual =  new  ScheduledThreadPoolExecutor( 1 new  ThreadFactory() {
     
         private  AtomicInteger atoInteger =  new  AtomicInteger( 0 );
     
         public  Thread newThread(Runnable r) {
             Thread t =  new  Thread(r);
             t.setName( "xxx-Thread " + atoInteger.getAndIncrement());
             return  t;
         }
     });
     
     /**
      * 设置调度shutdown后停止执行任务
      */
     static {
         schedual.setExecuteExistingDelayedTasksAfterShutdownPolicy( false );
         schedual.setContinueExistingPeriodicTasksAfterShutdownPolicy( false );
     }
     
     /**
      * 执行结果
      */
     private  ScheduledFuture<?> scheduledFuture;
     static  int  count;
     
     public  TestTimer() {
         // scheduledFuture = schedual.schedule(this, 20, TimeUnit.SECONDS); // 20秒后执行
         System.out.println( "调度时间:" + timeFormater.format(newDate()));
         // schedual.scheduleAtFixedRate(this, 5, 2, TimeUnit.SECONDS); // 5秒后每隔2秒执行一次(不论上次是否执行完毕)
         scheduledFuture = schedual.scheduleWithFixedDelay( this 5 2 , TimeUnit.SECONDS);  // 5秒后每隔2秒执行一次(在上次执行完毕后开始)
     }
     
     private  final  static  SimpleDateFormat timeFormater =  new  SimpleDateFormat( "HH:mm:ss:SSS" );
     
     public  void  run() {
         if (count++ >  5 ) {
             System.out.println( "执行已经满足5次,本次任务取消!" );
             scheduledFuture.cancel( false );
             schedual.shutdown();
             return ;
         }
         System.out.println( "运行时间:" + timeFormater.format( new  Date()));
         System.out.println( "当前线程名称:" + Thread.currentThread().getName());
         try {
             TimeUnit.SECONDS.sleep( 4 );
         catch (InterruptedException e) {
             e.printStackTrace();
         }
         System.out.println( "完成时间:" + timeFormater.format( new  Date()));
         System.out.println( "---------------------------" );
     }
     
}
 
 

 


以下转载的原文出处:http://www.360doc.com/content/12/0916/20/820209_236455178.shtml


Timer计时器有管理任务延迟执行("如1000ms后执行任务")以及周期性执行("如每500ms执行一次该任务")。但是,Timer存在一些缺陷,因此你应该考虑使用ScheduledThreadPoolExecutor作为代替品,Timer对调度的支持是基于绝对时间,而不是相对时间的,由此任务对系统时钟的改变是敏感的;ScheduledThreadExecutor只支持相对时间。

Timer的另一个问题在于,如果TimerTask抛出未检查的异常,Timer将会产生无法预料的行为。Timer线程并不捕获异常,所以TimerTask抛出的未检查的异常会终止timer线程。这种情况下,Timer也不会再重新恢复线程的执行了;它错误的认为整个Timer都被取消了。此时,已经被安排但尚未执行的TimerTask永远不会再执行了,新的任务也不能被调度了。

例子:

package com.concurrent.basic;

import java.util.Timer;
import java.util.TimerTask;

public class TimerTest {
private Timer timer = new Timer();

// 启动计时器
public void lanuchTimer() {
timer.schedule(new TimerTask() {
public void run() {
throw new RuntimeException();
}
}, 1000 * 3, 500);
}

// 向计时器添加一个任务
public void addOneTask() {
timer.schedule(new TimerTask() {
public void run() {
System.out.println("hello world");
}
}, 1000 * 1, 1000 * 5);
}

public static void main(String[] args) throws Exception {
TimerTest test = new TimerTest();
test.lanuchTimer();
Thread.sleep(1000 * 5);// 5秒钟之后添加一个新任务
test.addOneTask();
}
}
执行结果:

Java ScheduledThreadPoolExecutor 一个优于Timer、TimerTask的定时任务

你可能希望第二个没有异常的线程会一直运行下去,然而实际情况如程序所示5秒钟后就中止了,还伴随着一个异常,异常的消息是"Timer already cancelled"。ScheduledThreadPoolExector妥善地处理了这个异常的任务,所以说在java5.0或更高的JDK中,几乎没有理由再使用Timer了。

java5.0后提供

public interface ScheduledExecutorService 
extends  ExecutorService

一个 ExecutorService,可安排在给定的延迟后运行或定期执行的命令。

schedule 方法使用各种延迟创建任务,并返回一个可用于取消或检查执行的任务对象。scheduleAtFixedRate 和 scheduleWithFixedDelay 方法创建并执行某些在取消前一直定期运行的任务。

而且不受时钟限制。

例子:

package com.concurrent.basic;
import java.util.concurrent.Executors; 
import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.TimeUnit; 

public class ScheduledExecutorTest { 
//线程池能按时间计划来执行任务,允许用户设定计划执行任务的时间,int类型的参数是设定 
//线程池中线程的最小数目。当任务较多时,线程池可能会自动创建更多的工作线程来执行任务 
public ScheduledExecutorService scheduExec = Executors.newScheduledThreadPool(1); 
//启动计时器 
public void lanuchTimer(){ 
Runnable task = new Runnable() { 
public void run() { 
throw new RuntimeException(); 

}; 
scheduExec.scheduleWithFixedDelay(task, 1000*5, 1000*10, TimeUnit.MILLISECONDS); 

//添加新任务 
public void addOneTask(){ 
Runnable task = new Runnable() { 
public void run() { 
System.out.println("welcome to china"); 

}; 
scheduExec.scheduleWithFixedDelay(task, 1000*1, 1000, TimeUnit.MILLISECONDS); 


public static void main(String[] args) throws Exception { 
ScheduledExecutorTest test = new ScheduledExecutorTest(); 
test.lanuchTimer(); 
Thread.sleep(1000*5);//5秒钟之后添加新任务 
test.addOneTask();