当前位置:首页 > 开发 > 编程语言 > Java > 正文

浅谈Java定时器发展

发表于: 2014-11-18   作者:hacksin   来源:转载   浏览:
摘要: java在jdk1.3中推出了定时器类Timer,而后在jdk1.5后由Dou Lea从新开发出了支持多线程的ScheduleThreadPoolExecutor,从后者的表现来看,可以考虑完全替代Timer了。 Timer与ScheduleThreadPoolExecutor对比: 1.    Timer始于jdk1.3,其原理是利用一个TimerTask数组当作队列

java在jdk1.3中推出了定时器类Timer,而后在jdk1.5后由Dou Lea从新开发出了支持多线程的ScheduleThreadPoolExecutor,从后者的表现来看,可以考虑完全替代Timer了。

Timer与ScheduleThreadPoolExecutor对比:

1.

 

 Timer始于jdk1.3,其原理是利用一个TimerTask数组当作队列,将所有定时任务添加到此队列里面去。 然后启动一个线程,当队列为空时,此线程会阻塞,当队列里面有数据时,线程会去除一个TimerTask来判断

 是否到时间需要运行此任务,如果运行时间小于或等于当前时间时则开始运行任务。 由于其单线程的本质,所以会带来几个问题(详细代码在后面):

 第一,当我们添加到定时器中的任务比较耗时时,由于此定时器是单线程顺序执行定时器任务,所以会影响后续任务的按时执行。

 

//问题一示例:
m_timer.scheduleAtFixedRate(new TaskUseLongTime(), 1000, 5000);
m_timer.scheduleAtFixedRate(new TaskNormal(), 5000, 3000);

运行结果:
14:44:29: timer is sleeping 10 seconds
14:44:39: Task Normal executed
14:44:39: timer is sleeping 10 seconds
14:44:49: Task Normal executed
14:44:49: Task Normal executed
14:44:49: timer is sleeping 10 seconds

结果分析:TaskNormal任务无法保证3秒运行一次,其只能等待TaskUseLongTime运行结束后才可以。

 

 

 第二,Timer中的线程仅仅会捕获InterruptedException异常,所以如果我们自定义的定时任务里面没有捕获可能出现的异常而导致异常抛出后,

 

//问题二示例:
m_timer.schedule(new TaskThrowException(), 1000);
m_timer.schedule(new TaskNormal(), 2000);

运行结果:
14:47:37: Throw exception
Exception in thread "Timer-0" java.lang.RuntimeException
	at timer_test.TimerTest$TaskThrowException.run(TimerTest.java:85)
	at java.util.TimerThread.mainLoop(Timer.java:512)
	at java.util.TimerThread.run(Timer.java:462)

结果分析:
当前一个任务抛出异常后,后面的TaskNormal任务无法继续运行

 

 

 会导致我们的Timer线程停止,从而另后续的任务无法执行。

 第三,其无法处理多个同时发生的定时任务

 

//问题三示例:
m_timer.scheduleAtFixedRate(new TaskUseLongTime("timer1"), 1000, 15000);
m_timer.scheduleAtFixedRate(new TaskUseLongTime("timer2"), 1000, 15000);

运行结果:
14:50:16: timer1 is sleeping 10 seconds
14:50:26: timer2 is sleeping 10 seconds
14:50:36: timer2 is sleeping 10 seconds

结果分析:
我的启动时间均是1秒以后,但是timer1和timer2启动的时间明显不一致

 

 

 

代码示例:

 

/**
 * @filename TimerTest.java
 * @date     2014-11-18 
 */
package timer_test;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class TimerTest
{
	private final Timer m_timer = new Timer();
	
	public static void main(String[] args)
	{
		new TimerTest().test();
	}
	
	public void test()
	{
		//问题一示例:
		m_timer.scheduleAtFixedRate(new TaskUseLongTime(), 1000, 5000);
		m_timer.scheduleAtFixedRate(new TaskNormal(), 5000, 3000);
		
		//问题二示例:
//		m_timer.schedule(new TaskThrowException(), 1000);
//		m_timer.schedule(new TaskNormal(), 2000);
		
		//问题三示例:
//		m_timer.scheduleAtFixedRate(new TaskUseLongTime("timer1"), 1000, 5000);
//		m_timer.scheduleAtFixedRate(new TaskUseLongTime("timer2"), 1000, 5000);

	}
	
	private class TaskUseLongTime extends TimerTask
	{
		private String m_taskName = "timer";
		public TaskUseLongTime(){}
		
		public TaskUseLongTime(String taskName)
		{
			m_taskName = taskName;
		}
		@Override
		public void run()
		{
			try
			{
				System.out.println(getCurrentTime()+": "+m_taskName+" is sleeping 10 seconds");
				Thread.sleep(10000);
			} catch (InterruptedException e)
			{
			}
		}
	}
	
	private class TaskNormal extends TimerTask
	{
		@Override
		public void run()
		{
			System.out.println(getCurrentTime()+": Task Normal executed");
		}
	}
	
	private class TaskThrowException extends TimerTask
	{
		@Override
		public void run()
		{
			System.out.println(getCurrentTime()+": Throw exception");
			throw new RuntimeException();
		}
	}
	
	private String getCurrentTime()
	{
		return new SimpleDateFormat("HH:mm:ss").format(new Date());
	}
}

 

 

2.ScheduleThreadPoolExecutor

 

ScheduleThreadPoolExecutor始于jdk1.5,是由Dou Lea先生编写的,其利用ThreadPoolExecutor和DelayQueue巧妙的结合完成了多线程定时器的实现,解决了Timer中由于单线程而导致的上述三个缺陷。

 

问题一中的问题是因为单线程顺序执行导致后续任务无法按时完成,我们看到多线程可以很容易的解决此问题,同时我们注意到TaskUseLongTime的执行时间为10s(请看后续代码),我们定时任务间隔是5秒,但是从结果中发现我们的任务执行间隔却是10秒,所以我们可以判断ScheduleThreadPoolExecutor是采用每线程每任务的模式工作的。

 

//问题一:
m_timer.scheduleAtFixedRate(new TaskUseLongTime(), 1000, 5000, TimeUnit.MILLISECONDS);
m_timer.scheduleAtFixedRate(new TaskNormal(), 1000, 5000, TimeUnit.MILLISECONDS);

运行结果:
14:54:37: Task Normal executed
14:54:37: timer is sleeping 10 seconds
14:54:42: Task Normal executed
14:54:47: Task Normal executed
14:54:47: timer is sleeping 10 seconds
14:54:52: Task Normal executed

 

 

问题二中我们发现当抛出异常的任务执行后不影响其他任务的运行,同时我们发现在运行结果里面没有将我们的异常抛出,这是因为ScheduleThreadPoolExecutor类在执行完定时任务后会返回一个ScheduledFuture运行结果,不论结果是顺利完成还是有异常均会保存在这里。

 

 

//问题二:
m_timer.scheduleAtFixedRate(new TaskThrowException(), 1000, 5000, TimeUnit.MILLISECONDS);
m_timer.scheduleAtFixedRate(new TaskNormal(), 1000, 5000, TimeUnit.MILLISECONDS);

运行结果:
14:58:36: Throw exception
14:58:36: Task Normal executed
14:58:41: Task Normal executed
14:58:46: Task Normal executed
14:58:51: Task Normal executed
14:58:56: Task Normal executed

 

 问题三由于是多线程所以我们可以保证我们的定时任务可以同时执行

//问题三:
m_timer.scheduleAtFixedRate(new TaskUseLongTime("timer1"), 1000, 5000, TimeUnit.MILLISECONDS);
m_timer.scheduleAtFixedRate(new TaskUseLongTime("timer2"), 1000, 5000, TimeUnit.MILLISECONDS);

运行结果:
15:01:12: timer1 is sleeping 10 seconds
15:01:12: timer2 is sleeping 10 seconds
15:01:22: timer2 is sleeping 10 seconds
15:01:22: timer1 is sleeping 10 seconds
15:01:32: timer1 is sleeping 10 seconds
15:01:32: timer2 is sleeping 10 seconds

 

 详细代码:

/**
 * @filename ScheduleThreadPoolExecutorTest.java
 * @date     2014-11-18 
 */
package timer_test;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Callable;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ScheduleThreadPoolExecutorTest
{
	private final ScheduledThreadPoolExecutor m_timer = new ScheduledThreadPoolExecutor(10);
	
	public static void main(String[] args)
	{
		ScheduleThreadPoolExecutorTest timerTest = new ScheduleThreadPoolExecutorTest();
		timerTest.test();
		
		try
		{
			Thread.sleep(100000);
		} catch (InterruptedException e)
		{
		}finally
		{
			timerTest.shutdown();
		}
	}
	
	public void shutdown()
	{
		m_timer.shutdown();
	}
	
	public void test()
	{
		//问题一:
//		m_timer.scheduleAtFixedRate(new TaskUseLongTime(), 1000, 5000, TimeUnit.MILLISECONDS);
//		m_timer.scheduleAtFixedRate(new TaskNormal(), 1000, 5000, TimeUnit.MILLISECONDS);
		
		//问题二:
//		m_timer.scheduleAtFixedRate(new TaskThrowException(), 1000, 5000, TimeUnit.MILLISECONDS);
//		m_timer.scheduleAtFixedRate(new TaskNormal(), 1000, 5000, TimeUnit.MILLISECONDS);
		
		//问题三:
		m_timer.scheduleAtFixedRate(new TaskUseLongTime("timer1"), 1000, 5000, TimeUnit.MILLISECONDS);
		m_timer.scheduleAtFixedRate(new TaskUseLongTime("timer2"), 1000, 5000, TimeUnit.MILLISECONDS);
		
	}
	
	private class TaskUseLongTime implements Callable<Integer>, Runnable
	{
		private String m_taskName = "timer";
		private TaskUseLongTime(){}
		
		private TaskUseLongTime(String taskName)
		{
			m_taskName = taskName;
		}
		
		public void run()
		{
			try
			{
				System.out.println(getCurrentTime()+": "+m_taskName+" is sleeping 10 seconds");
				Thread.sleep(10000);
			} catch (InterruptedException e)
			{
			}
		}

		public Integer call() throws Exception
		{
			run();
			return 0;
		}
	}
	
	@SuppressWarnings("unused")
	private class TaskNormal implements Callable<Integer>, Runnable
	{
		
		public Integer call() throws Exception
		{
			run();
			return 0;
		}

		public void run()
		{
			System.out.println(getCurrentTime()+": Task Normal executed");
		}
	}
	
	@SuppressWarnings("unused")
	private class TaskThrowException implements Callable<Integer>, Runnable
	{
		public Integer call() throws Exception
		{
			System.out.println(getCurrentTime()+": Throw exception");
			throw new RuntimeException();
		}

		public void run()
		{
			System.out.println(getCurrentTime()+": Throw exception");
			throw new RuntimeException();
		}
	}
	
	
	private String getCurrentTime()
	{
		return new SimpleDateFormat("HH:mm:ss").format(new Date());
	}
}

 

 

 

 

 

浅谈Java定时器发展

  • 0

    开心

    开心

  • 0

    板砖

    板砖

  • 0

    感动

    感动

  • 0

    有用

    有用

  • 0

    疑问

    疑问

  • 0

    难过

    难过

  • 0

    无聊

    无聊

  • 0

    震惊

    震惊

编辑推荐
1.为什么专注于Java而不是C/C++? 一、首先,Java人讨厌C/C++ 对任何一名忠实的Javaer来说,我们都
1.为什么专注于Java而不是C/C++? 一、首先,Java人讨厌C/C++ 对任何一名忠实的Javaer来说,我们都
以前项目中写过类似的定时器,今天复习1下,自己建了个工程. 实现原理:创建servlet,应用服务器自动加
最近有同事提出在项目中使用JDK自带的定时器,之前的任务调度一直使用的是Quartz,对Timer没有研究
12月4日,受《通信产业报》好友毛启盈之约参加了由赛迪集团旗下《通信产业报》及多家业内知名IT媒体
Java 自带的定时器,有两个重要的类:TimerTask和Timer。 如下: 简单的使用: package com; import
之前在下载东西的时候,因为浏览器的下载,我想这个下载完后再开迅雷,然后就突发一个念头,有定时
关于资源管理业界主要框架,大家可以看我前面的文章。资源管理框架(mesos/YARN/coraca/Torca/Omega
关于资源管理业界主要框架,大家可以看我前面的文章。资源管理框架(mesos/YARN/coraca/Torca/Omega
关于资源管理业界主要框架,大家可以看我前面的文章。资源管理框架(mesos/YARN/coraca/Torca/Omega
版权所有 IT知识库 CopyRight © 2009-2015 IT知识库 IT610.com , All Rights Reserved. 京ICP备09083238号