在需要定时并且周期执行任务时,在最初的JAVA工具类库中,Timer可以实现任务的定时周期执行的需求,不过有一定的缺陷,比如,Timer是基于绝对时间而非相对时间,因此Timer对系统时钟比较敏感,本文就是讨论的Timer定时周期执行任务的问题。

代码清单1:TimerPrinter.java

package org.4spaces;

import java.util.Date;

import java.util.Random;

import java.util.TimerTask;

public class TimerPrinter extends TimerTask {

@Override

public void run() {

String base = "timerprinterbeginprinting.....";

Random random = new Random();

StringBuffer sb = new StringBuffer();

int number = 0;

for (int i = 0; i < 10; i++) {

number = random.nextInt(base.length());

sb.append(base.charAt(number));

}

System.out.println(new Date() + "," + sb.toString());

}

}

以上代码的功能是:输出代码执行时间和长度为10的字符串,这里我们将输出时间打印出来,近似认为是任务执行的时间。。

代码清单2:TimerLongTask.java

import java.util.TimerTask;

import java.util.concurrent.TimeUnit;

public class TimerLongTask extends TimerTask {

@Override

public void run() {

System.out.println("TimerLongTask:开始沉睡");

try {

TimeUnit.SECONDS.sleep(10);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("TimerLongTask:已经醒来");

}

}

以上代码的功能:启动了一个长任务,让任务沉睡10s。

代码清单3:TimerTest.java

package org.4spaces;

import java.util.Timer;

import java.util.concurrent.TimeUnit;

public class TimerTest {

public static void main(String[] args) throws InterruptedException {

Timer timer = new Timer();

timer.schedule(new TimerPrinter(), 1);

timer.schedule(new TimerLongTask(), 1);

timer.schedule(new TimerPrinter(), 2);

TimeUnit.SECONDS.sleep(20);

timer.cancel();

}

}

以上代码的功能:定时执行任务,我们先提交了一个打印任务,且让它延迟1毫秒执行,紧接着我们又提交了一个TimerLongTask长任务,且让它也延迟1毫秒执行,最后我们再提交一个打印任务,延迟2毫秒执行。然后让主线程沉睡20秒后关闭timer。执行结果如下:

Sat Nov 01 18:05:49 CST 2014,rigtr.meit

TimerLongTask:开始沉睡

TimerLongTask:已经醒来

Sat Nov 01 18:05:59 CST 2014,rgnneg.nni

从执行结果来看:第一次打印任务我们让延迟一秒后执行,沉睡任务我们也是设置的延迟一秒执行,第二次打印任务我们设置的是延迟2秒执行,执行结果第一次打印和第二次打印间隔为10秒,这个间隔正好是沉睡任务的时间,通过分析我们得出: Timer用来执行任务的线程只有一个,所以任务时逐一执行的。接下来我们查看一下源码验证一下,如下:

private TaskQueue queue = new TaskQueue();

private TimerThread thread = new TimerThread(queue);

这两行代码来自Timer源码,我们可以看到在第一次创建了Timer时就已经创建了一个thread和一个queue,因此只有一个线程来执行我们的任务。

那么Timer是如何来执行任务的?

首先我们调用timer.schedule方法,将任务提交到timer中,Timer中有很多重载的schedule方法,但它们都会调用同一个方法即sched方法。这个方法会将我们提交的任务添加到TaskQueue的队列中(即queue),在每次添加时都会根据nextExecutionTime大小来调整队列中任务的顺序,让nextExecutionTime最小的排在队列的最前端,nextExecutionTime最大的排在队列的最后端。在创建Timer时,我们同时也创建了一个TimerThread即thread,并且启动了这个线程:

public Timer(String name) {

thread.setName(name);

thread.start();

}

那么逐一执行的次序又是怎么样的呢?

我们来调整一下代码:

代码清单4:TimerTest.java

package org.4spaces;

import java.util.Timer;

import java.util.concurrent.TimeUnit;

public class TimerTest {

public static void main(String[] args) throws InterruptedException {

Timer timer = new Timer();

timer.schedule(new TimerPrinter(), 1);

timer.schedule(new TimerPrinter(), 2);

timer.schedule(new TimerLongTask(), 1);

TimeUnit.SECONDS.sleep(20);

timer.cancel();

}

}

执行结果:

Sat Nov 01 18:19:34 CST 2014,e.pmn.nimn

TimerLongTask:开始沉睡

TimerLongTask:已经醒来

Sat Nov 01 18:19:44 CST 2014,bnrrn..tgp

我们看到,打印任务2在沉睡任务执行之后再执行。

实际上,timer.schedule()这个方法,会将我们添加的任务,按照等待执行的时间长短排成队列,等待时间短的排在前面。

重复执行任务由方法:timer.scheduleAtFixedRate()来完成,比如:

Timer timer = new Timer();

timer.scheduleAtFixedRate(new TimerPrinter(), 3000, 5000);

表示,第一次执行时等待3s,然后每个5s执行一次该任务。

由于Timer只使用一个线程运行所有的任务,那么当一个任务抛出运行时异常后会有什么样的情形呢?其他的任务是否可以继续?我们已经有了前面的知识可以先猜想一个结果:因为Timer只使用一个线程运行所有的任务,所以当一个线程抛出运行时异常时,这个线程就基本挂了,不会在执行后续的任何代码,因此我们可以断言,当一个任务抛出运行时异常时,后续任务都不可以执行。为了证明这个猜想,我们需要一个可以抛出异常的任务,如下:

public class TimerExceptionTask extends TimerTask {

@Override

public void run() {

System.out.println("TimerExceptionTask: "+new Date());

throw new RuntimeException();

}

}

这个任务抛出一个运行时异常。接着我们需要定义一下我们任务执行的顺序:先执行一个正常的任务,然后在执行一个抛出异常的任务,最后在执行一个正常的任务,如下:

Timer timer = new Timer();

timer.schedule(new TimerTask1(), 1000);

timer.schedule(new TimerExceptionTask(), 3000);

timer.schedule(new TimerTask1(), 5000);

TimeUnit.SECONDS.sleep(6);

timer.cancel();

延迟1秒执行正常输出字符串的任务,延迟3秒执行抛出异常的任务,延迟5秒执行正常输出字符串的任务,看一下结果:

Thu Apr 21 13:40:23 CST 2011,lk7fjneyyu

TimerExceptionTask: Thu Apr 21 13:40:25 CST 2011

Exception in thread "Timer-0" java.lang.RuntimeException

at org.victorzhzh.concurrency.TimerExceptionTask.run(TimerExceptionTask.java:11)

at java.util.TimerThread.mainLoop(Timer.java:512)

at java.util.TimerThread.run(Timer.java:462)

并没有输出两个字符串,只执行了第一次的输出字符串任务,说明当抛出运行时异常时,其后续任务不可能被执行。鉴于Timer的缺陷,所以对它的使用还是要谨慎的,还好并发包中为我们提供了相应的替代品:ScheduledThreadPoolExecutor。

Java中Timer和ThreadPoolExecutor学习比较系列文章:

java捕获定时器抛出的异常_详细了解Java中定时器Timer的使用及缺陷分析相关推荐

  1. java 异常 不抛,java中不捕获或抛出的异常

    java中不捕获或抛出的异常 发布时间:2020-06-25 14:29:16 来源:亿速云 阅读:137 作者:Leah 这期内容当中小编将会给大家带来有关java中不捕获或抛出的异常,文章内容丰富 ...

  2. Spring捕获AOP抛出的异常

    Spring捕获AOP抛出的异常 背景 解决过程 最初方案 失败探索 添加AOP 继承SDK的AOP类 修改AOP生效条件 最终解决方案--BeanPostProcessor 总结 背景 在最近开发中 ...

  3. java 删除已画出的线_如何删除java中的绘制线?

    问题是如何删除旧行?我的意思是,只在屏幕上显示当前的x和y行,使两行之间的交点"跟随"鼠标指针. 这是更新的代码: import javax.swing.*; import jav ...

  4. 【java基础】java异常,捕获与抛出

    java异常,捕获与抛出 1.概念: 在java里,所有的异常都有一个共同的祖先Throwable(可抛出). Throwable:有两个重要的子类:Exception(异常)和Error(错误). ...

  5. 应该手动抛出什么异常?RuntimeException?

    Java程序员应该手动抛出什么异常?不能抛出RuntimeException吧? 收藏帖子 回复 秦三行 结帖率 96.88% if(sectionCodeT!=null && !&q ...

  6. Java中主线程如何捕获子线程抛出的异常

    Java中主线程如何捕获子线程抛出的异常 参考文章: (1)Java中主线程如何捕获子线程抛出的异常 (2)https://www.cnblogs.com/jpfss/p/10272885.html ...

  7. java 异常捕获抛出_JAVA异常处理捕获与抛出原理解析

    JAVA 异常 当代码运行出现错误导致程序终止运行或出现错误情况的状况,就是异常.异常不是指语法错误,即不属于编译错误,只有运行的程序才会有异常. 这个时候,JAVA 就提供了优秀的处理方法:异常处理 ...

  8. java 捕捉的异常抛出_Java异常抛出和捕获

    Java中把非正常情况分为两种,异常(Exception)和错误(Error). 异常.png Error:一般是指与虚拟机相关的问题(虚拟机错误.线程死锁等),这种错误无法回复或不可能捕获 Exce ...

  9. java中子类可否抛出两个父类抛出的异常的子类_父类的多个构造方法各自抛出不同的异常,子类的构造方法应该抛出哪个/些异常?...

    [情况描述]如下代码,在父类中定义了两个构造方法,各自throws不同的异常.当定义子类时,IDE会提示需要显示定义构造方法来抛出父类构造方法的异常.很自然地认为应该抛出父类所有构造方法的异常,然而只 ...

最新文章

  1. 文件读写io操作范例
  2. X-Content-Type-Options: nosniff
  3. Java编程入门(2.1):基础Java应用程序
  4. Js的Url中传递中文参数乱码的解决
  5. app 性能优化的那些事(二)
  6. 字符串太占内存了,我想了各种奇思淫巧对它进行压缩
  7. 教你如何快速入门python_如何快速入门python
  8. 计算机组装维护文献,组装计算机论文,关于《计算机组装维护》课程教学相关参考文献资料-免费论文范文...
  9. Windows下后台运行cmd启动的程序
  10. 用户画像案例一:汽车精准营销
  11. grub的boot loader安装在磁盘上的位置
  12. 模拟退火算法- 最短路径问题
  13. 模拟幅度调制系统抗干扰性能仿真分析[模板]
  14. B站(云e办)SpringBoot实战练习的Sql文件、前端Vue源码、后端springboot源码
  15. 平面2R机器人的运动学/动力学建模实例
  16. 《疯狂Java讲义》(第5版) 李刚
  17. 打造黑苹果(二)制作黑mac系统安装U盘
  18. 知识库管理-运维管理
  19. Matlab 图片批量复制到word中
  20. 电脑调节屏幕亮度快捷键失灵の解决方案

热门文章

  1. 转载 详解go语言GC
  2. Xcode 9 快速跳转到定义新姿势(Jump to Definition)
  3. tensorflow--logistic regression
  4. Numpy基础学习与总结
  5. java项目配置常见问题
  6. 如何用Windows Live Writer写网易博客
  7. Socket网络编程--简单Web服务器(2)
  8. 计算机视觉开源库OpenCV之图像翻转
  9. Django多进程中的查询错乱问题以及mysql gone away问题
  10. 约瑟夫环java链表_java使用链表实现约瑟夫环