Timer计时器有管理任务延迟执行("如1000ms后执行任务")以及周期性执行("如每500ms执行一次该任务")。
但是,Timer存在一些缺陷,因此你应该考虑使用ScheduledThreadPoolExecutor作为代替品,Timer对调度的支持是基于绝对时间,而不是相对时间的,由此任务对系统时钟的改变是敏感的;ScheduledThreadExecutor只支持相对时间。
Timer的另一个问题在于,如果TimerTask抛出未检查的异常,Timer将会产生无法预料的行为。
Timer线程并不捕获异常,所以TimerTask抛出的未检查的异常会终止timer 线程。
这种情况下,Timer也不会再重新恢复线程的执行了;它错误的认为整个Timer都被取消了。
此时,已经被安排但尚未执行的TimerTask永远不会再执行了,新的任务也不能被调度了。
例子:packagecom.concurrent.basic;importjava.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();nuchTimer();Thread.sleep(1000 * 5);// 5秒钟之后添加一个新任务test.addOneTask();}}执行结果:你可能希望第二个没有异常的线程会一直运行下去,然而实际情况如程序所示5秒钟后就中止了,还伴随着一个异常,异常的消息是"Timer already cancelled"。
ScheduledThreadPoolExector妥善地处理了这个异常的任务,所以说在java5.0或更高的JDK中,几乎没有理由再使用Timer了。
java5.0后提供public interface ScheduledExecutorServiceextends 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,LISECONDS);}//添加新任务public void addOneTask(){Runnable task = new Runnable() {public void run() {System.out.println("welcome to china");}};scheduExec.scheduleWithFixedDelay(task, 1000*1, 1000,LISECONDS);}public static void main(String[] args) throws Exception { ScheduledExecutorTest test = new ScheduledExecutorTest();nuchTimer();Thread.sleep(1000*5);//5秒钟之后添加新任务test.addOneTask();}}但是ScheduledThreadPoolExecutor也有不利的地方,就是只能按相对的时间的,而不能设置具体某个时刻之后执行,如每天晚上12点定时执行任务之类的要求使用Timer更合适,如果是周期性的重复工作可以考虑使用ScheduledThreadPoolExecutor。
Java定时任务ScheduledThreadPoolExecutor2012-08-05 13:15:00以前定时任务一直用Timer这个类,后来发现ScheduledThreadPoolExecutor功能更强大,我们先看个简单的示例,然后再看看API中的描述:这个定时任务是我的项目中,每隔5分钟去检查设备的在线状态的。
[java]public class CheckDeviceStateExcuter {private static final Log log =LogFactory.getLog(CheckDeviceStateExcuter.class);private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);private static DeviceDaodeviceDao = new DeviceDaoImpl();private static List<DeviceDTO> devices = newArrayList<DeviceDTO>();// invoke DLL method to get the details of devicestatic JoymindCommDLLLib instance =JoymindCommDLLLib.INSTANCE;// check statespublic static void checkStart() {final Runnable checker = new Runnable() {public void run() {System.out.println("check");devices = deviceDao.queryDevices();for(DeviceDTO device : devices){String ip = device.getIp();String id = "auto_refresh_" + ip;String iniPath = XmlOperationTool.PLAYLIST_TEMPFILE_FOLDER + id+ ".ini";int flag = instance.GetSysInfo(ip, iniPath);if(flag == 1){// get ini fileSystemInfoDTO info = null;try {info = FileOperationTool.parseIni(iniPath);device.setMacAdd(info.getMacAddress()); device.setIp(info.getIp());device.setGateway(info.getGateway()); device.setOnlineState("在线");device.setBootTime(info.getBootTime()); device.setDeviceVersion(info.getVersion()); device.setAvailableSpace(info.getFreedisk());device.setpNo(info.getpNo());device.setWidth(info.getWidth());device.setHeight(info.getHeight());device.setStorage(info.getStorage()); device.setTime(info.getTime());device.setPrgTotal(info.getPrgTotal()); device.setPrgIndex(info.getPrgIndex()); device.setStatusNo(info.getStatus());if (info.getStorage().equals("1")) {device.setStorageName("FLASH存储");}if (info.getStorage().equals("2")) {device.setStorageName("RAM存储");}if (info.getStorage().equals("3")) {device.setStorageName("SD卡存储");}device.setCurrentPlaylist("");device.setCurrentTemplate("");device.setLastCommunicateTime(""); device.setCurrentTransferFileName(""); device.setCurrentTransferSpeed("");device.setCurrentPercentage("");device.setVolume("");device.setAutoBootTime("");device.setAutoShutdownTime("");device.setPlayingVideo("");device.setProgramUpdateTime("");device.setProgramUpdateState("");} catch (IOException e1) {if (log.isErrorEnabled()) {log.error(e1.getMessage());}e1.printStackTrace();}booleanaddFlag = deviceDao.updateDevice(device);if (addFlag) {if (log.isDebugEnabled()) {log.debug("auto update device "+device.getName()+" successfully"); }} else {if (log.isErrorEnabled()) {log.error("auto update device failed !!!");}}}else{deviceDao.updateDevice(ip, "离线");if (log.isDebugEnabled()) {log.debug("auto update device "+device.getName()+" statue offline"); }}}}};// 此处的checker是一个线程,1表示启动延迟1个单位开始执行这个线程,然后每隔5分钟执行一次,单位是分钟final ScheduledFuture<?>checkerHandle =scheduler.scheduleAtFixedRate(checker, 1, 5, TimeUnit.MINUTES);// 这里注释的地方是取消这个定时任务的,是在3600天后停止,因为我这里是检查设备的,所以除非当程序退出才自动停止这个定时任务/*scheduler.schedule(new Runnable() {public void run() {checkerHandle.cancel(true);}}, 60 * 60, TimeUnit.DAYS);*/}/*** @paramargs*/public static void main(String[] args) {// TODO Auto-generated method stub}再看看API的具体信息,总之这是个非常实用的类public class ScheduledThreadPoolExecutorextends ThreadPoolExecutorimplements ScheduledExecutorServiceThreadPoolExecutor,它可另行安排在给定的延迟后运行命令,或者定期执行命令。