http://victorzhzh.iteye.com/blog/1011635

上一篇中我们看到了Timer的不足之处,本篇我们将围绕这些不足之处看看ScheduledThreadPoolExecutor是如何优化的。

为了研究方便我们需要两个类:

Java代码  
  1. public class Task1 implements Callable<String> {
  2. @Override
  3. public String call() throws Exception {
  4. String base = "abcdefghijklmnopqrstuvwxyz0123456789";
  5. Random random = new Random();
  6. StringBuffer sb = new StringBuffer();
  7. for (int i = 0; i < 10; i++) {
  8. int number = random.nextInt(base.length());
  9. sb.append(base.charAt(number));
  10. }
  11. System.out.println("Task1 running: " + new Date());
  12. return sb.toString();
  13. }
  14. }

生成含有10个字符的字符串,使用Callable接口目的是我们不再任务中直接输出结果,而主动取获取任务的结果

Java代码  
  1. public class LongTask implements Callable<String> {
  2. @Override
  3. public String call() throws Exception {
  4. System.out.println("LongTask running: "+new Date());
  5. TimeUnit.SECONDS.sleep(10);
  6. return "success";
  7. }
  8. }

长任务类,这里我们让任务沉睡10秒然后返回一个“success”

下面我们来分析一下ScheduledThreadPoolExecutor:

1、Timer中单线程问题是否在ScheduledThreadPoolExecutor中存在?

我们先来看一下面的程序:

Java代码  
  1. public class ScheduledThreadPoolExec {
  2. public static void main(String[] args) throws InterruptedException,
  3. ExecutionException {
  4. <strong><span style="color: #ff0000;">ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(
  5. 2);</span>
  6. </strong>
  7. ScheduledFuture future1 = executor.schedule(new Task1(), 5,
  8. TimeUnit.SECONDS);
  9. ScheduledFuture future2 = executor.schedule(new LongTask(), 3,
  10. TimeUnit.SECONDS);
  11. BlockingQueue<ScheduledFuture> blockingQueue = new ArrayBlockingQueue<ScheduledFuture>(
  12. 2, true);
  13. blockingQueue.add(future2);
  14. blockingQueue.add(future1);
  15. System.out.println(new Date());
  16. while (!blockingQueue.isEmpty()) {
  17. ScheduledFuture future = blockingQueue.poll();
  18. if (!future.isDone())
  19. blockingQueue.add(future);
  20. else
  21. System.out.println(future.get());
  22. }
  23. System.out.println(new Date());
  24. executor.shutdown();
  25. }
  26. }

首先,我们定义了一个ScheduledThreadPoolExecutor它的池长度是2。接着提交了两个任务:第一个任务将延迟5秒执行,第二个任务将延迟3秒执行。我们建立了一个BlockingQueue,用它来存储了ScheduledFuture,使用ScheduledFuture可以获得任务的执行结果。在一个while循环中,我们每次将一个ScheduledFuture从队列中弹出,验证它是否被执行,如果没有被执行则再次将它加入队列中,如果被执行了,这使用ScheduledFuture的get方法获取任务执行的结果。看一下执行结果:

Java代码  
  1. Thu Apr 21 19:23:02 CST 2011
  2. LongTask running: Thu Apr 21 19:23:05 CST 2011
  3. Task1 running: Thu Apr 21 19:23:07 CST 2011
  4. h1o2wd942e
  5. success
  6. Thu Apr 21 19:23:15 CST 2011

我们看到长任务先运行,因为长任务只等待了3秒,然后是输出字符串的任务运行,两个任务开始时间相差2秒,而先输出了字符串而后才是长任务运行的结果success,最后我们查看一下整体的开始和结束时间相差了13秒。

这说明在ScheduledThreadPoolExecutor中它不是以一个线程运行任务的,而是以多个线程,如果用一个线程运行任务,那么长任务运行完之前是不会运行输出字符串任务的。其实这个“多个任务“是我们自己指定的注意一下标红的代码,如果我们把这行代码改为:

Java代码  
  1. ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);

那么运行结果就会发生变化,

Java代码  
  1. Thu Apr 21 19:36:56 CST 2011
  2. LongTask running: Thu Apr 21 19:36:59 CST 2011
  3. success
  4. Task1 running: Thu Apr 21 19:37:09 CST 2011
  5. y981iqd0or
  6. Thu Apr 21 19:37:09 CST 2011

这时其实和使用Timer运行结果是一样的。任务是在一个线程里顺序执行的。

2、Timer中一但有运行时异常报出后续任务是否还会正常运行?

为了研究这个问题,我们还是需要一个能够抛出异常的任务,如下:

Java代码  
  1. public class TimerExceptionTask extends TimerTask {
  2. @Override
  3. public void run() {
  4. System.out.println("TimerExceptionTask: "+new Date());
  5. throw new RuntimeException();
  6. }
  7. }

我们对上面运行任务的代码做一点点小小的修改,先运行两个抛出异常的任务,如下:

Java代码  
  1. public class ScheduledThreadPoolExec {
  2. public static void main(String[] args) throws InterruptedException,
  3. ExecutionException {
  4. ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(
  5. 2);
  6. ScheduledFuture future1 = executor.schedule(new Task1(), 5,
  7. TimeUnit.SECONDS);
  8. ScheduledFuture future2 = executor.schedule(new LongTask(), 3,
  9. TimeUnit.SECONDS);
  10. <strong><span style="color: #ff0000;">executor.schedule(new TimerExceptionTask(), 1, TimeUnit.SECONDS);
  11. executor.schedule(new TimerExceptionTask(), 2, TimeUnit.SECONDS);</span>
  12. </strong>
  13. BlockingQueue<ScheduledFuture> blockingQueue = new ArrayBlockingQueue<ScheduledFuture>(
  14. 2, true);
  15. blockingQueue.add(future2);
  16. blockingQueue.add(future1);
  17. System.out.println(new Date());
  18. while (!blockingQueue.isEmpty()) {
  19. ScheduledFuture future = blockingQueue.poll();
  20. if (!future.isDone())
  21. blockingQueue.add(future);
  22. else
  23. System.out.println(future.get());
  24. }
  25. System.out.println(new Date());
  26. executor.shutdown();
  27. }
  28. }

注意,标红的代码,如果这两个代码抛出错误后会影响后续任务,那么就应该在此终止,但是看一下结果,

Java代码  
  1. Thu Apr 21 19:40:15 CST 2011
  2. TimerExceptionTask: Thu Apr 21 19:40:16 CST 2011
  3. TimerExceptionTask: Thu Apr 21 19:40:17 CST 2011
  4. LongTask running: Thu Apr 21 19:40:18 CST 2011
  5. Task1 running: Thu Apr 21 19:40:20 CST 2011
  6. v5gcf01iiz
  7. success
  8. Thu Apr 21 19:40:28 CST 2011

后续任务仍然执行,可能会有朋友说:“你上面的池设置的是2,所以很有可能是那两个抛出异常的任务都在同一个线程中执行,而另一个线程执行了后续的任务”。那我们就把ScheduledThreadPoolExecutor设置成1看看,结果如下:

Java代码  
  1. Thu Apr 21 19:43:00 CST 2011
  2. TimerExceptionTask: Thu Apr 21 19:43:01 CST 2011
  3. TimerExceptionTask: Thu Apr 21 19:43:02 CST 2011
  4. LongTask running: Thu Apr 21 19:43:03 CST 2011
  5. success
  6. Task1 running: Thu Apr 21 19:43:13 CST 2011
  7. 33kgv8onnd
  8. Thu Apr 21 19:43:13 CST 2011

后续任务也执行了,所以说ScheduledThreadPoolExecutor不会像Timer那样有线程泄漏现象。

对于周期性执行和Timer很类似这里就不再举例了。

转载于:https://www.cnblogs.com/senior-engineer/p/5000143.html

定时且周期性的任务研究II--ScheduledThreadPoolExecutor相关推荐

  1. 如何调度spark程序_如何定时,周期性的运行程序?Python APScheduler实现任务灵活调度...

    在我们的开发工作中,时常会有这样的开发需求,如需要定时或者周期性的运行某些程序,因此经常用到一些定时服务,如在 Linux系统中使用 Crond 服务实现程序的定时运行. 在 Python中也有这样的 ...

  2. floquet端口x极化入射波_AnsoftHFSS在周期性异向介质研究中的仿真方法.pdf

    AnsoftHFSS在周期性异向介质研究中的仿真方法 Ansoft 2008 优秀论文 Ansoft HFSS 在周期性异向介质研究中的仿真方法 龚建强,褚庆昕 (华南理工大学电子与信息学院 广州 5 ...

  3. Java四种线程创建的思路

    一.哪四种 传统的是继承thread类和实现runnable接口,java5以后又有实现callable接口和java的线程池获得. callable相比于runnable,多了返回值,抛出了异常. ...

  4. java线程不执行_java线程池,阿里为什么不允许使用Executors?

    带着问题 阿里Java代码规范为什么不允许使用Executors快速创建线程池? 下面的代码输出是什么? ThreadPoolExecutor executor = new ThreadPoolExe ...

  5. PHP中空格占位数吗,html内的空格占位

    NPOI读取Excel 数据 转... public DataTable am_Decode() { DataTable table = new DataTable(); string[] strAs ...

  6. td lte pss同步matlab仿真,TD-LTE系统小区搜索PSS定时同步的研究

    随着移动互联网的发展,终端用户对于数据业务的需求呈爆炸式的增长,为了满足用户对移动无线宽带的需求,TD-LTE网络成为移动互联网的重要解决方案.在TD-LTE系统中,小区搜索是无线链路的关键步骤,是用 ...

  7. matlab对有周期性噪声的图像去噪,数字图像中去除周期性噪声研究.doc

    摘要:图像增强是数字图像处理相对简单却最具艺术性的领域之一,其目的是消除噪声,显现被模糊的细节或突出感兴趣区域.经常采用的手段分空域和频域两类,其中频域更是给我们提供了不同的视角,简化了许多复杂的算法 ...

  8. 11.定时任务定时线程池详解

    3.1 新增定时任务池 11.定时任务&定时线程池详解 ​ 当我们不用任务框架时,我们想自己写一个定时任务时,我们能想起那个工具类呢?Timer ?还有吗?不知道了,下面我们要讲下Schedu ...

  9. @Scheduled定时

    目录 一.项目中常遇到的坑 二.线程池相关内容 2.1 .线程池的创建: 2.1.1  Java通过Executors提供四种线程池 三. @Scheduled的工作机制,源码分析 1.@Schedu ...

最新文章

  1. php扇形分布图,PHP制作3D扇形统计图以及对图片进行缩放操作实例
  2. 工业互联网不只是网络:网络是基础,平台是关键
  3. Mybatis系列(三):Mybatis实现关联表查询
  4. 有网友提问,关于本地XML转JSON的小工具
  5. 计算机硬件知识教学的信息化手段,《计算机硬件组成》教学设计
  6. c语言uint32_使C语言实现面向对象的三个要素,你掌握了吗?
  7. 现在的年轻人不够努力了吗?是什么原因?
  8. Python 在数据科学中一直打压 R 语言?
  9. TableView Within Alert
  10. [转]软件开发的“三重门”
  11. 修改docker网桥模式下的网络地址
  12. Master Reactor Manager Worker TaskWorker(Task)
  13. NOIp2010 机器翻译
  14. 马上:网络故障排查的思路和方法
  15. 【笔记整理】网络攻防技术
  16. 【字符编码转换】使用iconv
  17. Android静默拍照(无感知拍照)
  18. WSL2 安装 CUDA(Win11)
  19. 云服务器系统结构图,云服务器系统结构图
  20. 歇逼了兄弟,心态崩了

热门文章

  1. 安卓逆向—霸哥磁力搜索apk过签名校验
  2. Ubuntu 18.04.6 允许root用户登录桌面
  3. 智星云服务器之云主机使用教程简记
  4. Failed to load the JNI shared library 的解决方法
  5. 计算机网络技术评估与备选方案,计算机网络技术业个人职业生涯规划书.doc
  6. 深度学习与OpenCV DNN模块:权威指南
  7. 选用pg的优点和缺点
  8. 记录---Testin上新手测试用例设计实战---碎乐3.2.0
  9. 【以太坊】什么是雷电网络 Raiden network
  10. python是自由开放源代码软件_开放源代码定义之历史篇