java定时器的实现用什么实现

用户名:雪飘七月
文章数:64
评论数:24
访问量:153217
注册日期:
阅读量:1297
阅读量:3317
阅读量:426844
阅读量:1115061
51CTO推荐博文
一、什么是定时器
&&&&&&& 定时器的用途方方面面,早上叫我们起床的闹钟,洗衣机、微波炉、电视机、空调都有定时设置。
&&&&&&& 而定时器一般可以分为两个部分:触发装置和触发事件。而触发装置中又有对时间的控制。
二、我们的软件定时器
&&&&&&& 在java中,我们的软件定时器也是分为这两个部分。
&&&&&& 采用quartz实现触发器时,首先是通过一个Scheduler来对触发器及出发事件的控制。触发器中含有触发开始时间、触发结束时间、触发次数和触发周期的参数调用方法来对以上属性进行控制。而触发事件是通过继承Job接口的方式实现,最后在触发时自动调用触发事件。
三、java定时器实例解析
首先,我的工程调用了一下三个jar包
quartz-all-1.6.1.jar
定时器核心类
commons-collections.jar
commons-logging-1.0.4.jar
&以下实例是启动后三秒开始执行第一次,每隔10秒
定时器测试类
&&&&&&public&class&Test&{ &&&&&&public&static&void&main(String[]&args){ &&&&&&&&&InitScheduler.init(); &&&&&} &}&
时间管理类Scheduler
&&&&&&public&class&InitScheduler&{ &&&&&&private&static&Scheduler&sched&=&null;; &&&&& &&&&&public&static&void&init(){ &&&&&&&&&try&{ &&&&&&&&&&&&&&&&&&&&&&&&&&sched&=&(new&StdSchedulerFactory()).getScheduler(); &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&JobDetail&jobDetail&=&new&JobDetail(&myjob&, &&&&&&&&&&&&&&&&&&&&&&groupsimpletrigger&,&MyJob.class); &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&SimpleTrigger&simpletrigger&=&new&SimpleTrigger( &&&&&&&&&&&&&&&&&&&&&&simpletrigger&,& &&&&&&&&&&&&&&&&&&&&&&groupsimpletrigger&,& &&&&&&&&&&&&&&&&&&&&&new&Date(System.currentTimeMillis()&+&3000), &&&&&&&&&&&&&&&&&&&&&null, &&&&&&&&&&&&&&&&&&&&&SimpleTrigger.REPEAT_INDEFINITELY,& &&&&&&&&&&&&&&&&&&&&&10L&*&1000L); &&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&sched.scheduleJob(jobDetail,&simpletrigger); &&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&sched.start(); &&&&&&&&&}&catch&(SchedulerException&e)&{ &&&&&&&&&&&&&&&&&&&&&&&&&&e.printStackTrace(); &&&&&&&&&} &&&&&} &}&
继承了Job接口的任务类
&&&&&&public&class&MyJob&implements&Job{ &&&&&&&&&&&@Override&&&&&public&void&execute(JobExecutionContext&arg0)&throws&JobExecutionException&{ &&&&&&&&&&&&&&&&&&&&&&&&&&&System.out.println(&执行myjob时间:&+&new&Date()); &&&&&} &}&
&本文出自 “” 博客,请务必保留此出处
了这篇文章
附件下载:  
类别:┆阅读(0)┆评论(0)
请输入验证码:JAVA中定时器的使用
- 薄荷红茶 - ITeye技术网站
1-------------------------------------------------------------
在JAVA中实现定时器功能要用的二个类是Timer,TimerTask
Timer类是用来执行任务的类,它接受一个TimerTask做参数Timer有两种执行任务的模式,最常用的是schedule,它可以以两种方式执行任务:1:在某个时间(Data),2:在某个固定的时间之后(int delay).这两种方式都可以指定任务执行的频率,本文有二个例子,一个是简单的一个是用了内部类1.简单实例
先写一个类public class TimeTest {public static void main(String[] args) {
Timer timer = new Timer();
timer.schedule(new MyTask(),);}然后再写个类 public class MyTask
extends TimerTask{
public void run() {
System.out.println("开始运行");
}}这样就可以完成一个简单的定时器,但是还有一种方法就是把这二个类写入到一个类中,也就是内部类了2.内部类public class SerchRun {
static void startRun(){
Timer timer = new Timer();
TimerTask task =new TimerTask(){
public void run(){
System.out.println("开始运行"); //在这写你要调用的方法
timer.scheduleAtFixedRate(task, new Date(),2000);//当前时间开始起动 每次间隔2秒再启动
// timer.scheduleAtFixedRate(task, ); // 1秒后启动
每次间隔2秒再启动
public static void main(String[] args) {
SerchRun.startRun();
schedule和scheduleAtFixedRate的区别在于,如果指定开始执行的时间在当前系统运行时间之前,scheduleAtFixedRate会把已经过去的时间也作为周期执行,而schedule不会把过去的时间算上。
SimpleDateFormat fTime = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date d1 = fTime.parse(" 14:10:00");
t.scheduleAtFixedRate(new TimerTask(){
public void run()
System.out.println("this is task you do6");
},d1,3*60*1000);
间隔时间是3分钟,指定开始时间是 14:10:00,如果我在14:17:00分执行这个程序,那么会立刻打印3次
this is task you do6
//14:10this is task you do6
//14:13this is task you do6
并且注意,下一次执行是在14:19 而不是 14:20。就是说是从指定的开始时间开始计时,而不是从执行时间开始计时。
但是上面如果用schedule方法,间隔时间是3分钟,指定开始时间是 14:10:00,那么在14:17:00分执行这个程序,则立即执行程序一次。并且下一次的执行时间是 14:20,而不是从14:10开始算的周期(14:19)。
2-------------------------------------------------------------
在很多情况下,我们都需要用到定时器
比如:定时删除数据库的某些垃圾信息(即没有用到,但是占着位置的东西) 在CMS中,我们用定时器来定时发布文章,定时删除上传的没有用到的文件….. 定时器,顾名思义一下,在规定的时间提醒某件事情。 从这种解释中,我们不难理解,定时器需要用到的东西有两样:1,定时;2,任务(执行的事件) 先来解决以下第一个问题:定时 在java编程中,用于定时的类有:Timer 在这个类中,有很多方法,最常用的是schedule方法,在这个类中重载了好几个这个方法,但是主要的用途还是用于在某个时间点开始,定时执行某个任务,这个方法保证了定时器整体功能的实现 第二个问题:任务 有了时间,我们就要给这个机器一个任务,让它在规定的时间点后执行这个任务,这个任务类可以继承TimerTask类来实现,这样的话,就可以得到一个新的任务类,这个任务类主要覆盖一个run()方法,这个方法里面我们写的是需要执行的具体任务,这个类在被引用的时候就会执行这个方法。 下面看方法: 任务类: import java.util.*; public class Task extends TimerTask {
public void run() {
System.out.println("我是Task"+"现在时间是:" + new Date());
} } 定时类: import java.util.T import java.util.C import java.util.GregorianC import java.util.D public class Dingshiqi {
public static void main(String[] args) {
Timer timer = new Timer();
Task task = new Task();
timer.schedule(task, new Date(), 2000);
} } 这样实现的效果是,每隔2秒,就会输出“我是Task,现在时间是(当前的时间)”。
定时器,我们可以用在servlet中,这个是比较常用的,下面说下如何运用servlet实现定时效果 把某些属性值写在xml文件中,然后在servlet中取得该值,然后在servlet的init方法调用定时功能,最后,destroy()来销毁定时器 xml中设置一些相应处理的servlet: &servlet&
&description&This is the description of my J2EE component&/description&
&display-name&This is the display name of my J2EE component&/display-name&
&servlet-name&Admin_servlet&/servlet-name&
&servlet-class&com.cbh.lmodules_article.servlet.Admin_servlet&/servlet-class&
&init-param&
&param-name&startTask&/param-name&
&param-value&true&/param-value&
&/init-param&
&init-param&
&param-name&intervalTime&/param-name&
&param-value&1&/param-value&
&/init-param&
&load-on-startup&1&/load-on-startup&
&/servlet&
servlet中的init方法启动定时器 public void init() throws ServletException {
ServletContext context = getServletContext();
// (true为用定时间刷新缓存)
String startTask =getInitParameter("startTask");
// 定时刷新时间(分钟)
//Long delay = Long.parseLong(getInitParameter("intervalTime"));
// 启动定时器
if (startTask.equals("true")) {
timer1 = new Timer(true);
task1 = new Timer_task(context);
System.out.println("TimerServlet2定时器已启动");
timer1.schedule(task1,0, 60*1000);
System.out.println("TimerServlet2已经添加任务调度表");
} servlet中的destroy方法销毁定时器 public void destroy() {
super.destroy();
if (timer1 != null) {
timer1.cancel();
System.out.println("TimerServlet2定时器已销毁");
} 在servlet中运用定时器的话,那么就需要建立和任务的关联,怎么建立关联呢? public class Timer_task extends TimerTask {
private ServletC
private static boolean isRunning =
public Timer_task(ServletContext context){
this.context = //有参构造来实现与servlet的关联
Admin_service as=new Admin_service();
public void run() {
as.delte("");
3-------------------------------------------------------------
java.util.Timer
一种线程设施,用于安排以后在后台线程中执行的任务。可安排任务执行一次,或者定期重复执行。此类是线程安全的:多个线程可以共享单个 Timer 对象而无需进行外部同步。
java.util.TimerTask
由 Timer 安排为一次执行或重复执行的任务。
如何通过这两个类来完成定时操作功能呢?具体是使用方法,下面通过一个具体demo来进行说明。
本demo实现这样一个功能,在系统运行期间,每30分钟,系统自动检查连接池中的可用连接数,并输出到日志中。
首先创建一个需要定时执行的任务类,这个任务类需要继承TimerTask,然后重写run()方法,run()方法体中的代码就是定时需要执行的操作,在本demo中,就是获取连接池中当前可用连接数,并输出到日志中,具体实现代码如下:
publicclass TaskAvailableConnectNumber extends TimerTask {
private Logger log = Logger.getLogger(TaskAvailableConnectNumber.class);
private ConnectionPool pool=ConnectionPool.getInstance();
publicvoid run() {
log.debug("当前连接池中可用连接数"+pool.getAvailableConnectNumber());
下面定义一个监听器,负责在应用服务器启动时打开定时器,监听器需要实现ServletContextListener接口,并重写其中的contextInitialized()和contextDestroyed()方法,代码如下:
publicclass OnLineListener implements ServletContextListener{
private Logger log = Logger.getLogger(OnLineListener.class);
Timer timer = null;
//在应用服务器启动时,会执行该方法
publicvoid contextInitialized(ServletContextEvent arg0) {
//创建一个定时器,用于安排需要定时执行的任务。
timer = new Timer();
//为定时器安排需要定时执行的任务,该任务就是前面创建的任务类TaskAvailableConnectNumber,并指定该任务每30分钟执行一次。
timer.schedule(new TaskAvailableConnectNumber(), 0, 30*60*1000);
log.debug("启动定时器");
//应用服务器关闭时,会执行该方法,完成关闭定时器的操作。
publicvoid contextDestroyed(ServletContextEvent arg0) {
if(timer!=null){
timer.cancel();//关闭定时器
log.debug("-----定时器销毁--------");
监听器要想正常运行,需要在文件中进行配置,配置信息如下:
&!-- 监听器配置开始 --&
&listener&
&listener-class&
cn.sdfi.listen.OnLineListener
&/listener-class&
&/listener&
&!-- 监听器配置结束 --&
以上步骤完成后,一个简单的定时器就算开发完成了
浏览: 280101 次
来自: 深圳
怎么我用第一种方法不行呢 alert(document.rea ...
有帮助,至少可以解决了目前所遇到的问题!谢谢..
String actionMessage = new Stri ...
Sev7en_jun 写道GOOD
客气,互相交流。。问题对人有帮助,内容完整,我也想知道答案
问题没有实际价值,缺少关键内容,没有改进余地
想实现一个功能,需要定期查看一个表,并发送消息。
在Java中,有哪些好的实现方案?资源耗费情况如何?容错能力好的有哪些?
请高手支招。
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
Quartz 是个开放源码项目,提供了丰富的作业调度集。在这篇文章中,软件工程师 Michael Lipton 和 IT 架构师
Soobaek Jang 对 Quartz API 进行了介绍,从对框架的一般概述开始,并以一系列展示 Quart
基本特性的代码示例作为结束。在阅读完本文并看过代码示例后,您应当能够把 Quartz 的基本特性应用到任何 Java(TM) 应用程序中。
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
对于java本身提供的功能来说, 就是Timer 和 ScheduledThreadPoolExecutor了.
我找了这个网页:
和我一直的理解是一致的. 每一个Timer对应一个后台线程, 其接收到的TimerTasker 被放入队列中(具体实现应该是一个小顶堆). 适合少量的, 短的任务.
如果要处理多个, 长时间的任务, 并且对时间 和 并行处理有要求的, 用ScheduledThreadPoolExecutor.
如果在Java EE环境下, 还可以考虑EJB timer
以前用过, 印象最深的就是 1). 可以和transaction一起用, 如果事务回滚, timer的创建/取消也会回滚.
2). persistent. 应用服务器重启后, timer不会丢失.
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
推荐使用Spring的task,通过标注方式实现,方便简单
&task:executor id="executor" pool-size="5" /&
&task:scheduler id="scheduler" pool-size="10" /&
&task:annotation-driven executor="executor" scheduler="scheduler" /&
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
spring task , 如果你在用spring的话
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
如果是简单的定时调度,使用Timer就够了,如果复杂的调度任务,可以考虑使用Quartz,容错能力要看你写的代码了,不管使用哪种方式,Timer和Quartz都是稳定的。
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
java自带的java.util.Timer
Spring3.0以后的task
开源项目Quartz
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
几种任务调度的 Java 实现方法与比较
同步到新浪微博
分享到微博?
Hi,欢迎来到 SegmentFault 技术社区!⊙▽⊙ 在这里,你可以提出编程相关的疑惑,关注感兴趣的问题,对认可的回答投赞同票;大家会帮你解决编程的问题,和你探讨技术更新,为你的回答投上赞同票。
明天提醒我
关闭理由:
删除理由:
忽略理由:
推广(招聘、广告、SEO 等)方面的内容
与已有问题重复(请编辑该提问指向已有相同问题)
答非所问,不符合答题要求
宜作评论而非答案
带有人身攻击、辱骂、仇恨等违反条款的内容
无法获得确切结果的问题
非开发直接相关的问题
非技术提问的讨论型问题
其他原因(请补充说明)
我要该,理由是:
扫扫下载 Appjava定时任务实现的几种方式 - 推酷
java定时任务实现的几种方式
在开发测试工具的应用后台,经常听到同事说要做个定时任务把做日志处理,或者数据清理,包括做些复杂的业务计算逻辑,在选择定时任务的时候,怎么能够快速实现,并且选择一种更适合自己的方式呢?&我这里把定时任务的实现收集整理了一些方法,希望可以帮到刚开始做定时任务的同学,写得不对的地方请指正。
一& Java 基本的定时任务,总结方法有三种:
1.1&& 创建一个thread,然后让它在while循环里一直运行着,通过sleep方法来达到定时任务的效果;
1.2&& 用Timer和TimerTask与第一种方法相比有如下好处:
当启动和去取消任务时可以控制
第一次执行任务时可以指定你想要的delay时间
1.3&& 用 ScheduledExecutorService是从 的java.util.concurrent里,做为并发工具类被引进的,这是最理想的定时任务实现方式,相比于上两个方法,它有以下好处:
相比于Timer的单线程,它是通过线程池的方式来执行任务的
可以很灵活的去设定第一次执行任务delay时间
提供了良好的约定,以便设定执行的时间间隔
定时任务,总结方式也有三种:
2.1&&& ScheduledTimerTask:& Spring的ScheduledTimerTask定义了一个定时器任务的运行周期,遗憾的是,你可以指定任务执行的频度,但你无法精确指定它何时运行,这就需要用到第二种Quartz进行任务调度;
创建一个业务任务,在Spring配置文件中声明 ;
在Spring 配置文件中,配置ScheduledTimerTask ,并且关联上自定义的任务实例;
启动定时器,Spring的TimerFactoryBean负责启动定时任务
2.2&&& 使用 Quartz:
首先还是老样子定义业务逻辑任务:
在 Spring 中声明并且 配置作业调度的触发方式
这里 Quartz的作业触发器有两种,分别是
org.springframework.scheduling.quartz.SimpleTriggerBean
org.springframework.scheduling.quartz.CronTriggerBean
第一种SimpleTriggerBean,只支持按照一定频度调用任务,如每隔一段时间运行一次。
&beanid=&simpleTrigger&&class=&org.springframework.scheduling.quartz.SimpleTriggerBean& &
& & &propertyname=&jobDetail&&ref=&myJob&& /&
& & &propertyname=&startDelay&&value=&0&& /& &!--&调度工厂实例化后,经过0秒开始执行调度&--&&&
& & &propertyname=&repeatInterval&&value=&2000&& /& &!--&每2秒调度一次&--&&&
第二种CronTriggerBean,支持到指定时间运行一次,如每天12:00运行一次,如上配置;
配置调度工厂
org.springframework.scheduling.quartz.SchedulerFactoryBean,代码如上;
启动你的应用即可
2.3&& 使用 Spring-Task
&&&&&&&&&Spring自带的定时任务工具,spring task,可以将它比作一个轻量级的Quartz,而且使用起来很简单,除spring相关的包外不需要额外的包,而且支持注解和配置文件两种:
第一步:编写任务类;TaskJob,method job1& --代码省略
& &&&&&&& 第二步:在spring配置文件头中添加命名空间及描述
&beansxmlns=&http://www.springframework.org/schema/beans&&&
xmlns:task=&http://www.springframework.org/schema/task&
xsi:schemaLocation=&http://www.springframework.org/schema/task
& & & &&第三步:spring配置文件中设置具体的任务
&task:scheduled-tasks&
&task:scheduledref=&taskJob&&method=&job1&&cron=&0&*&*&*&*&?& /&
&/task:scheduled-tasks&
&context:component-scanbase-package=&com.alibaba.mytask&& /&
说明:ref参数指定的即任务类,method指定的即需要运行的方法,cron及cronExpression表达式,具体写法这里不介绍了,&context:component-scan base-package=&com.alibaba.mytask& /&spring扫描注解用的。
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致一个java定时器实现 -
- ITeye技术网站
博客分类:
之前有几个需要用到定时器超时的场景,比如线程池大小有限,如何让task不死等,但又不至于一旦队列满就直接reject或者让提交线程来做,但后来还是用让提交线程做事的方式来做,也就是并行暂时退化成了串行。
定时器有几个关键部分,1.定时扫描机制和设定,2.超时处理callback,3.超时前成功返回cancel.定时器的实现有很多种。下面的代码主要是团队使用的改造过的HashedWheelTimer,内部有很多细节,但不妨碍理解机制。
业务使用代码:
Timeout timeout = this.timer.newTimeout(new TimerTask() {
public void run(Timeout timeout) throws Exception {
// 如果连接没有推送元,则断开连接
if (!timeout.isCancelled() && conn.isConnected()) {
if (conn.getAttribute(CONN_META_DATA_ATTR) == null) {
log.error(LOGPREFX + "连接" + conn.getRemoteSocketAddress() + "没有推送元信息,主动关闭连接");
conn.close(false);
}, this.delay, TimeUnit.SECONDS);
// 已经添加了,取消最新的
if (conn.setAttributeIfAbsent(CONN_METADATA_TIMEOUT_ATTR, timeout) != null) {
timeout.cancel();
定时器实现代码
* A {@link Timer} optimized for approximated I/O timeout scheduling.
* &h3&Tick Duration&/h3&
* As described with 'approximated', this timer does not execute the scheduled
* {@link TimerTask} on time. {@link HashedWheelTimer}, on every tick, will
* check if there are any {@link TimerTask}s behind the schedule and execute
* You can increase or decrease the accuracy of the execution timing by
* specifying smaller or larger tick duration in the constructor. In most
* network applications, I/O timeout does not need to be accurate. Therefore,
* the default tick duration is 100 milliseconds and you will not need to try
* different configurations in most cases.
* &h3&Ticks per Wheel (Wheel Size)&/h3&
* {@link HashedWheelTimer} maintains a data structure called 'wheel'. To put
* simply, a wheel is a hash table of {@link TimerTask}s whose hash function is
* 'dead line of the task'. The default number of ticks per wheel (i.e. the size
* of the wheel) is 512. You could specify a larger value if you are going to
* schedule a lot of timeouts.
* &h3&Implementation Details&/h3&
* {@link HashedWheelTimer} is based on &a
* href="http://cseweb.ucsd.edu/users/varghese/"&George Varghese&/a& and Tony
* Lauck's paper, &a
* href="http://cseweb.ucsd.edu/users/varghese/PAPERS/twheel.ps.Z"&'Hashed and
* Hierarchical Timing Wheels: data structures to efficiently implement a timer
* facility'&/a&. More comprehensive slides are located &a
* href="http://www.cse.wustl.edu/~cdgill/courses/cs6874/TimingWheels.ppt"
* &here&/a&.
* @author &a href="http://www.jboss.org/netty/"&The Netty Project&/a&
* @author &a href="http://gleamynode.net/"&Trustin Lee&/a&
public class HashedWheelTimer implements Timer {
static final Log logger = LogFactory.getLog(HashedWheelTimer.class);
private static final AtomicInteger id = new AtomicInteger();
// I'd say 64 active timer threads are obvious misuse.
private static final int MISUSE_WARNING_THRESHOLD = 64;
private static final AtomicInteger activeInstances = new AtomicInteger();
private static final AtomicBoolean loggedMisuseWarning = new AtomicBoolean();
private final Worker worker = new Worker();
final Thread workerT
final AtomicBoolean shutdown = new AtomicBoolean();
private final long roundD
final long tickD
final Set&HashedWheelTimeout&[]
final ReusableIterator&HashedWheelTimeout&[]
final ReadWriteLock lock = new ReentrantReadWriteLock();
private volatile int wheelC
private final AtomicInteger size = new AtomicInteger(0);
final int maxTimerC
* Creates a new timer with the default thread factory (
* {@link Executors#defaultThreadFactory()}), default tick duration, and
* default number of ticks per wheel.
public HashedWheelTimer() {
this(Executors.defaultThreadFactory());
* Creates a new timer with the default thread factory (
* {@link Executors#defaultThreadFactory()}) and default number of ticks per
* @param tickDuration
the duration between tick
* @param unit
the time unit of the {@code tickDuration}
public HashedWheelTimer(long tickDuration, TimeUnit unit) {
this(Executors.defaultThreadFactory(), tickDuration, unit);
* Creates a new timer with the default thread factory (
* {@link Executors#defaultThreadFactory()}).
* @param tickDuration
the duration between tick
* @param unit
the time unit of the {@code tickDuration}
* @param ticksPerWheel
the size of the wheel
public HashedWheelTimer(long tickDuration, TimeUnit unit, int ticksPerWheel, int maxTimerCapacity) {
this(Executors.defaultThreadFactory(), tickDuration, unit, ticksPerWheel, maxTimerCapacity);
* Creates a new timer with the default tick duration and default number of
* ticks per wheel.
* @param threadFactory
a {@link ThreadFactory} that creates a background
{@link Thread} which is dedicated to {@link TimerTask}
execution.
public HashedWheelTimer(ThreadFactory threadFactory) {
this(threadFactory, 100, TimeUnit.MILLISECONDS);
* 返回当前timer个数
public int size() {
return this.size.get();
* Creates a new timer with the default number of ticks per wheel.
* @param threadFactory
a {@link ThreadFactory} that creates a background
{@link Thread} which is dedicated to {@link TimerTask}
execution.
* @param tickDuration
the duration between tick
* @param unit
the time unit of the {@code tickDuration}
public HashedWheelTimer(ThreadFactory threadFactory, long tickDuration, TimeUnit unit) {
this(threadFactory, tickDuration, unit, 512, 50000);
* Creates a new timer.
* @param threadFactory
a {@link ThreadFactory} that creates a background
{@link Thread} which is dedicated to {@link TimerTask}
execution.
* @param tickDuration
the duration between tick
* @param unit
the time unit of the {@code tickDuration}
* @param ticksPerWheel
* @param maxTimerCapacity
the size of the wheel
public HashedWheelTimer(ThreadFactory threadFactory, long tickDuration, TimeUnit unit, int ticksPerWheel,
int maxTimerCapacity) {
if (threadFactory == null) {
throw new NullPointerException("threadFactory");
if (unit == null) {
throw new NullPointerException("unit");
if (tickDuration &= 0) {
throw new IllegalArgumentException("tickDuration must be greater than 0: " + tickDuration);
if (ticksPerWheel &= 0) {
throw new IllegalArgumentException("ticksPerWheel must be greater than 0: " + ticksPerWheel);
if (maxTimerCapacity &= 0) {
throw new IllegalArgumentException("maxTimerCapacity must be greater than 0: " + maxTimerCapacity);
// Normalize ticksPerWheel to power of two and initialize the wheel.
this.wheel = createWheel(ticksPerWheel);
this.iterators = createIterators(this.wheel);
this.maxTimerCapacity = maxTimerC
this.mask = this.wheel.length - 1;
// Convert tickDuration to milliseconds.
this.tickDuration = tickDuration = unit.toMillis(tickDuration);
// Prevent overflow.
if (tickDuration == Long.MAX_VALUE || tickDuration &= Long.MAX_VALUE / this.wheel.length) {
throw new IllegalArgumentException("tickDuration is too long: " + tickDuration + ' ' + unit);
this.roundDuration = tickDuration * this.wheel.
this.workerThread =
threadFactory.newThread(new ThreadRenamingRunnable(this.worker, "Hashed wheel timer #"
+ id.incrementAndGet()));
// Misuse check
int activeInstances = HashedWheelTimer.activeInstances.incrementAndGet();
if (activeInstances &= MISUSE_WARNING_THRESHOLD && pareAndSet(false, true)) {
logger.debug("There are too many active " + HashedWheelTimer.class.getSimpleName() + " instances ("
+ activeInstances + ") - you should share the small number "
+ "of instances to avoid excessive resource consumption.");
@SuppressWarnings("unchecked")
private static Set&HashedWheelTimeout&[] createWheel(int ticksPerWheel) {
if (ticksPerWheel &= 0) {
throw new IllegalArgumentException("ticksPerWheel must be greater than 0: " + ticksPerWheel);
if (ticksPerWheel & ) {
throw new IllegalArgumentException("ticksPerWheel may not be greater than 2^30: " + ticksPerWheel);
ticksPerWheel = normalizeTicksPerWheel(ticksPerWheel);
Set&HashedWheelTimeout&[] wheel = new Set[ticksPerWheel];
for (int i = 0; i & wheel. i++) {
wheel[i] =
new MapBackedSet&HashedWheelTimeout&(new ConcurrentIdentityHashMap&HashedWheelTimeout, Boolean&(16,
0.95f, 4));
@SuppressWarnings("unchecked")
private static ReusableIterator&HashedWheelTimeout&[] createIterators(Set&HashedWheelTimeout&[] wheel) {
ReusableIterator&HashedWheelTimeout&[] iterators = new ReusableIterator[wheel.length];
for (int i = 0; i & wheel. i++) {
iterators[i] = (ReusableIterator&HashedWheelTimeout&) wheel[i].iterator();
private static int normalizeTicksPerWheel(int ticksPerWheel) {
int normalizedTicksPerWheel = 1;
while (normalizedTicksPerWheel & ticksPerWheel) {
normalizedTicksPerWheel &&= 1;
return normalizedTicksPerW
* Starts the background thread explicitly. The background thread will start
* automatically on demand even if you did not call this method.
* @throws IllegalStateException
if this timer has been {@linkplain #stop() stopped} already
public synchronized void start() {
if (this.shutdown.get()) {
throw new IllegalStateException("cannot be started once stopped");
if (!this.workerThread.isAlive()) {
this.workerThread.start();
public synchronized Set&Timeout& stop() {
if (!pareAndSet(false, true)) {
return Collections.emptySet();
boolean interrupted =
while (this.workerThread.isAlive()) {
this.workerThread.interrupt();
this.workerThread.join(100);
catch (InterruptedException e) {
interrupted =
if (interrupted) {
Thread.currentThread().interrupt();
activeInstances.decrementAndGet();
Set&Timeout& unprocessedTimeouts = new HashSet&Timeout&();
for (Set&HashedWheelTimeout& bucket : this.wheel) {
unprocessedTimeouts.addAll(bucket);
bucket.clear();
return Collections.unmodifiableSet(unprocessedTimeouts);
public Timeout newTimeout(TimerTask task, long delay, TimeUnit unit) {
final long currentTime = System.currentTimeMillis();
if (task == null) {
throw new NullPointerException("task");
if (unit == null) {
throw new NullPointerException("unit");
delay = unit.toMillis(delay);
if (delay & this.tickDuration) {
delay = this.tickD
if (!this.workerThread.isAlive()) {
this.start();
if (this.size.get() &= this.maxTimerCapacity) {
throw new RejectedExecutionException("Timer size " + this.size + " is great than maxTimerCapacity "
+ this.maxTimerCapacity);
// Prepare the required parameters to create the timeout object.
HashedWheelT
final long lastRoundDelay = delay % this.roundD
final long lastTickDelay = delay % this.tickD
final long relativeIndex = lastRoundDelay / this.tickDuration + (lastTickDelay != 0 ? 1 : 0);
final long deadline = currentTime +
final long remainingRounds = delay / this.roundDuration - (delay % this.roundDuration == 0 ? 1 : 0);
// Add the timeout to the wheel.
this.lock.readLock().lock();
new HashedWheelTimeout(task, deadline, (int) (this.wheelCursor + relativeIndex & this.mask),
remainingRounds);
this.wheel[timeout.stopIndex].add(timeout);
this.lock.readLock().unlock();
this.size.incrementAndGet();
private final class Worker implements Runnable {
private long startT
Worker() {
public void run() {
List&HashedWheelTimeout& expiredTimeouts = new ArrayList&HashedWheelTimeout&();
this.startTime = System.currentTimeMillis();
this.tick = 1;
while (!HashedWheelTimer.this.shutdown.get()) {
this.waitForNextTick();
this.fetchExpiredTimeouts(expiredTimeouts);
this.notifyExpiredTimeouts(expiredTimeouts);
private void fetchExpiredTimeouts(List&HashedWheelTimeout& expiredTimeouts) {
// Find the expired timeouts and decrease the round counter
// if necessary. Note that we don't send the notification
// immediately to make sure the listeners are called without
// an exclusive lock.
HashedWheelTimer.this.lock.writeLock().lock();
int oldBucketHead = HashedWheelTimer.this.wheelC
int newBucketHead = oldBucketHead + 1 & HashedWheelTimer.this.
HashedWheelTimer.this.wheelCursor = newBucketH
ReusableIterator&HashedWheelTimeout& i = HashedWheelTimer.this.iterators[oldBucketHead];
this.fetchExpiredTimeouts(expiredTimeouts, i);
HashedWheelTimer.this.lock.writeLock().unlock();
private void fetchExpiredTimeouts(List&HashedWheelTimeout& expiredTimeouts,
ReusableIterator&HashedWheelTimeout& i) {
long currentDeadline = System.currentTimeMillis() + HashedWheelTimer.this.tickD
i.rewind();
while (i.hasNext()) {
HashedWheelTimeout timeout = i.next();
if (timeout.remainingRounds &= 0) {
if (timeout.deadline & currentDeadline) {
i.remove();
expiredTimeouts.add(timeout);
// A rare case where a timeout is put for the next
// round: just wait for the next round.
timeout.remainingRounds--;
private void notifyExpiredTimeouts(List&HashedWheelTimeout& expiredTimeouts) {
// Notify the expired timeouts.
for (int i = expiredTimeouts.size() - 1; i &= 0; i--) {
expiredTimeouts.get(i).expire();
HashedWheelTimer.this.size.decrementAndGet();
// Clean up the temporary list.
expiredTimeouts.clear();
private void waitForNextTick() {
for (;;) {
final long currentTime = System.currentTimeMillis();
final long sleepTime = HashedWheelTimer.this.tickDuration * this.tick - (currentTime - this.startTime);
if (sleepTime &= 0) {
Thread.sleep(sleepTime);
catch (InterruptedException e) {
if (HashedWheelTimer.this.shutdown.get()) {
// Reset the tick if overflow is expected.
if (HashedWheelTimer.this.tickDuration * this.tick & Long.MAX_VALUE - HashedWheelTimer.this.tickDuration) {
this.startTime = System.currentTimeMillis();
this.tick = 1;
// Increase the tick if overflow is not likely to happen.
this.tick++;
private final class HashedWheelTimeout implements Timeout {
private final TimerT
final int stopI
volatile long remainingR
private volati
HashedWheelTimeout(TimerTask task, long deadline, int stopIndex, long remainingRounds) {
this.task =
this.deadline =
this.stopIndex = stopI
this.remainingRounds = remainingR
public Timer getTimer() {
return HashedWheelTimer.
public TimerTask getTask() {
return this.
public void cancel() {
if (this.isExpired()) {
this.cancelled =
// Might be called more than once, but doesn't matter.
if (HashedWheelTimer.this.wheel[this.stopIndex].remove(this)) {
HashedWheelTimer.this.size.decrementAndGet();
public boolean isCancelled() {
return this.
public boolean isExpired() {
return this.cancelled || System.currentTimeMillis() & this.
public void expire() {
if (this.cancelled) {
this.task.run(this);
catch (Throwable t) {
logger.warn("An exception was thrown by " + TimerTask.class.getSimpleName() + ".", t);
public String toString() {
long currentTime = System.currentTimeMillis();
long remaining = this.deadline - currentT
StringBuilder buf = new StringBuilder(192);
buf.append(this.getClass().getSimpleName());
buf.append('(');
buf.append("deadline: ");
if (remaining & 0) {
buf.append(remaining);
buf.append(" ms later, ");
else if (remaining & 0) {
buf.append(-remaining);
buf.append(" ms ago, ");
buf.append("now, ");
if (this.isCancelled()) {
buf.append(", cancelled");
return buf.append(')').toString();
浏览: 102857 次
来自: 杭州
浏览量:3026
好牛逼 竟然解决了我别的问题
在使用这个类的时候workerId应该怎么传
增加虚拟节点解决数据均衡的问题。我有个疑问:1.使用虚拟节点后 ...
wangjian95 写道tddl.....?不是
tddl.....?

我要回帖

更多关于 java 定时器实现原理 的文章

 

随机推荐