参考资料
定时方案一直使用Timer,因为调用的不频繁,对时间把控也没有那么绝对的严格,所以也没发现问题。 说一下需求: 以10s为一个周期,每隔1s钟检查一下服务器是否回复,10s钟时仍没有回复,则进入额外20s的超时判断,第30s上仍没回复则提示超时。 使用Timer时,以10s为单位启停一次,实际上是0延迟1秒为周期,用全局变量做计数器去统计10s,结果整个周期最大的时候竟然出现了2s的误差,这是不能接受的。 于是考虑使用JDK5的多线程包ScheduledExecutorService 网上的资料多,而且跟官网范例区别不大,基本只演示了怎么启动任务,怎么停止所有任务,可是我要控制单个任务的停止,资料就很少。 参考了上面那个帖子之后,使用idea做了测试
static int time_1 = 0,time_2=0; static Future futureDelay,futureFixedDelay; public static void main(String[] args){ //定时功能测试 ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3); System.out.println("before"+System.currentTimeMillis()); // schedule:延迟多长时间之后只执行一次,执行完自动结束; scheduledExecutorService.schedule(new Runnable() { @Override public void run() { System.out.println("schedule single"+System.currentTimeMillis()); } },0, TimeUnit.MILLISECONDS); // scheduledAtFixedRate:延迟指定时间后执行一次,之后按照固定的时长周期执行; time_1=0; time_2=0; futureDelay = scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { try{ time_1++; System.out.println("schedule delay"+time_1+" mills:"+System.currentTimeMillis()); if(time_1>=10){ futureDelay.cancel(false); System.out.println("schedule delay finished "+System.currentTimeMillis()); } }catch (Exception e){ e.printStackTrace(); System.out.println("schedule Exception:"+e.getMessage()); } } },0,1000,TimeUnit.MILLISECONDS); // scheduledWithFixedDelay:延迟指定时间后执行一次,之后按照:上一次任务执行时长 + 周期的时长 的时间去周期执行; futureFixedDelay=scheduledExecutorService.scheduleWithFixedDelay(new Runnable() { @Override public void run() { try{ time_2++; System.out.println("schedule FixedDelay"+time_2+" mills:"+System.currentTimeMillis()); if(time_2>=10){ futureFixedDelay.cancel(false); System.out.println("schedule FixedDelay finished " + System.currentTimeMillis()+" size:"+scheduledExecutorService.shutdownNow().size()); } }catch (Exception e){ e.printStackTrace(); System.out.println("schedule Exception:"+e.getMessage()); } } },5000,3000,TimeUnit.MILLISECONDS); }我这里只放了测试代码,添加了三个定时任务,分别测试了 Executors.newScheduledThreadPool(1) Executors.newScheduledThreadPool(2) Executors.newScheduledThreadPool(3) Executors.newSingleThreadScheduledExecutor() 以上四种情况感觉区别不是很大,误差在5毫秒以内,我最后使用Executors.newSingleThreadScheduledExecutor()感觉就可以了
实际上ScheduledExecutorService 有五个函数可以构建对象,实际上最常用的是newScheduledThreadPool(N)和newSingleThreadScheduledExecutor() 1)newSingleThreadScheduledExecutor :new DelegatedScheduledExecutorService(new ScheduledThreadPoolExecutor(1)) 2)newSingleThreadScheduledExecutor(ThreadFactory threadFactory) :new DelegatedScheduledExecutorService(new ScheduledThreadPoolExecutor(1, threadFactory)); 3)newScheduledThreadPool(int corePoolSize) :new ScheduledThreadPoolExecutor(corePoolSize); 4)newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory) :new ScheduledThreadPoolExecutor(corePoolSize, threadFactory); 5)unconfigurableScheduledExecutorService(ScheduledExecutorService executor) :new DelegatedScheduledExecutorService(executor);
之后测试了重复开线程
static int time_1 = 0,time_2=0; static ArrayList<Future> futures; static Future futureDelay,futureFixedDelay; static ScheduledExecutorService scheduledExecutorService; public static void main(String[] args){ futures = new ArrayList<>(); //定时功能测试 scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); System.out.println("before"+System.currentTimeMillis()); // scheduledAtFixedRate:延迟指定时间后执行一次,之后按照固定的时长周期执行; time_1=0; time_2=1; futures.add(scheduledExecutorService.scheduleAtFixedRate(getTask("task"+time_2),0,1000,TimeUnit.MILLISECONDS)); // futureDelay = ; } private static Runnable getTask(String taskName){ return new Runnable() { @Override public void run() { try{ time_1++; System.out.println(taskName+" schedule delay"+time_1+" mills:"+System.currentTimeMillis()); if(time_1>=10){ time_2++; //如果设置true,则表示可以取消正在执行过程中的任务 futures.get(futures.size()-1).cancel(true); System.out.println(taskName+" finished "+System.currentTimeMillis()); if(time_2<=5) { time_1=0; futures.add(scheduledExecutorService.scheduleAtFixedRate(getTask("task"+time_2),0,1000,TimeUnit.MILLISECONDS)); // futureDelay = scheduledExecutorService.scheduleAtFixedRate(getTask("task" + time_2), 0, 1000, TimeUnit.MILLISECONDS); } } }catch (Exception e){ e.printStackTrace(); System.out.println(taskName+" schedule Exception:"+e.getMessage()); } } }; }