欢迎探讨,如有错误敬请指正

如需转载,请注明出处 http://www.cnblogs.com/nullzx/

1. ScheduleExecutorService接口、ScheduledFuture接口

从图中可以看出ScheduledExecutorService接口继承了ExecutorService接口,同时还添加了有关提交定时任务的四个方法。

public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit)
//向定时任务线程池提交一个延时Runnable任务(仅执行一次)
public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit);
//向定时任务线程池提交一个延时的Callable任务(仅执行一次)
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay,
                                                  long period, TimeUnit unit)
//向定时任务线程池提交一个固定时间间隔执行的任务
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay,
                                                      long delay, TimeUnit unit);
//向定时任务线程池提交一个固定延时间隔执行的任务

固定时间间隔的任务不论每次任务花费多少时间,下次任务开始执行时间是确定的,当然执行任务的时间不能超过执行周期。

固定延时间隔的任务是指每次执行完任务以后都延时一个固定的时间。由于操作系统调度以及每次任务执行的语句可能不同,所以每次任务执行所花费的时间是不确定的,也就导致了每次任务的执行周期存在一定的波动。

注意:定时或延时任务中所涉及到时间、周期不能保证实时性及准确性,实际运行中会有一定的误差。

从上图可以还可以看出ScheduledThreadPoolExecutor还直接继承了ThreadPoolExecutor。这样做是为了利用ThreadPoolExecutor已实现的方法。

可以向定时任务线程池提交普通任务。对于定时任务线程池而言,普通任务只不过是延时执行时间为0,周期为0的任务。

从上述四个方法中的返回值可以看出,当向线程池提交任务时会返回一个ScheduleFuture接口的对象。通过下图可以看出,ScheduledFuture接口继承了Delayed和Future接口。我们可以通过ScheduleFutured对象的cancel方法可以结束一个定时任务。

在ScheduledThreadPoolExecutor中阻塞队列存储的是ScheduledFutureTask对象,它是任务真正的载体。但是ScheduledFutureTask对象同样可以看做Runnable对象,所以同样可以使用ThreadPoolExecutor中的方法来处理它。

2. ScheduledThreadPoolExecutor的运行原理

在图中,我们将ScheduleFutureTask简称为SFT

在定时任务线程池中存储任务的队列是具有优先性质的阻塞队列。在这个队列中离下次执行时间最近的任务位于队首(关于优先队列的原理请参照本博客后续数据结构的相关内容)。线程每次通过优先队列的take方法获取任务。如果队列为空take方法阻塞,否则take方法从队首获取带执行的任务(即ScheduleFutureTask对象),然后从任务的getDelay方法获取应当延时的时间,再通过带参数的await方法进行延时。当延时时间已到,则开始执行任务(在执行之前还要检测这个任务是否已被取消),执行完毕以后继续判断这是否是一个周期任务。如果不是,调用take方法获取新任务,重复上述操作。如果是计算下一次执行的时间,然后调用队列的add方法将这个任务再次入列。入列完成后,继续调用take方法获取新任务,这样重复的执行下去。

以上就是定时任务线程池工作的最基本原理,实际上take、add、任务的取消等过程比较复杂,图中也没有说明线程在执行await方法时队首元素改变时的情况。如果想继续了解,请参阅本博客“ScheduledThreadPoolExecutor源代码分析”的文章。

3. ScheduleThreadPoolExecutor与Timer相比的优势。

(1)Timer是基于绝对时间的延时执行或周期执行,当系统时间改变,则任务的执行会受到的影响。而ScheduleThreadPoolExecutore中,任务时基于相对时间进行周期或延时操作。

(2)Timer也可以提交多个TimeTask任务,但只有一个线程来执行所有的TimeTask,这样并发性受到影响。而ScheduleThreadPoolExecutore可以设定池中线程的数量。

(3)Timer不会捕获TimerTask的异常,只是简单地停止,这样势必会影响其他TimeTask的执行。而ScheduleThreadPoolExecutore中,如果一个线程因某些原因停止,线程池可以自动创建新的线程来维护池中线程的数量。

4. 使用示例

package javalearning;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

public class ScheduledThreadPoolExecutorDemo {
	static class TimerTask implements Runnable{
		private String id;
		public TimerTask(String id){
			this.id = id;
		}
		@Override
		public void run(){
			System.out.println(id);
		}
	}

	public static void main(String[] args) throws InterruptedException{
		ScheduledExecutorService ses = Executors.newScheduledThreadPool(2);
		ScheduledFuture sfa = ses.scheduleAtFixedRate(new TimerTask("a"), 200,
				                                    1000, TimeUnit.MILLISECONDS);
		ScheduledFuture sfb = ses.scheduleAtFixedRate(new TimerTask("b"), 400,
				                                    1000, TimeUnit.MILLISECONDS);
		ScheduledFuture sfc = ses.scheduleAtFixedRate(new TimerTask("c"), 600,
				                                    1000, TimeUnit.MILLISECONDS);
		ScheduledFuture sfd = ses.scheduleAtFixedRate(new TimerTask("d"), 800,
				                                    1000, TimeUnit.MILLISECONDS);
		Thread.sleep(5000);
		sfa.cancel(true);
		Thread.sleep(5000);
		ses.shutdown();
	}
}

在这个示例中,定义了一个内部类TimerTask,它实现了Runnable接口。在main方法中创建了一个定时任务线程池,向它提交了四个任务a,b,c,d。四个任务起始的延时时间分别是200ms、400ms、600ms、800ms,执行周期都为1000ms。5秒以后取消了定时任务a的执行。又过了5秒,关闭了线程池。默认情况下关闭线程池会结束池所有的任务。

以下是运行结果
a
b
c
d
a
b
c
d
a
b
c
d
a
b
c
d
a
b
c
d
b
c
d
b
c
d
b
c
d
b
c
d
b
c
d

5.参考内容

[1] http://janeky.iteye.com/blog/770441

ScheduleThreadPoolExecutor的工作原理与使用示例的更多相关文章

  1. Optaplanner规划引擎的工作原理及简单示例(2)

    开篇 在前面一篇关于规划引擎Optapalnner的文章里(Optaplanner规划引擎的工作原理及简单示例(1)),老农介绍了应用Optaplanner过程中需要掌握的一些基本概念,这些概念有且于 ...

  2. JAVA NIO工作原理及代码示例

    简介:本文主要介绍了JAVA NIO中的Buffer, Channel, Selector的工作原理以及使用它们的若干注意事项,最后是利用它们实现服务器和客户端通信的代码实例. 欢迎探讨,如有错误敬请 ...

  3. Optaplanner规划引擎的工作原理及简单示例(1)

    在之前的文章中,老猿已介绍过APS及规划的相关内容,也对Optaplanner相关的概念和一些使用示例进行过介绍,接下来的文章中,我会自己做一个规划小程序 - 一个关于把任务分配到不同的机台上进行作来 ...

  4. Java并发包中CountDownLatch的工作原理、使用示例

    1. CountDownLatch的介绍 CountDownLatch是一个同步工具,它主要用线程执行之间的协作.CountDownLatch 的作用和 Thread.join() 方法类似,让一些线 ...

  5. Java并发包中CyclicBarrier的工作原理、使用示例

    1. CyclicBarrier的介绍与源码分析 CyclicBarrier 的字面意思是可循环(Cyclic)使用的屏障(Barrier).它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时 ...

  6. 【原】Learning Spark (Python版) 学习笔记(三)----工作原理、调优与Spark SQL

    周末的任务是更新Learning Spark系列第三篇,以为自己写不完了,但为了改正拖延症,还是得完成给自己定的任务啊 = =.这三章主要讲Spark的运行过程(本地+集群),性能调优以及Spark ...

  7. 浏览器内部工作原理--作者:Tali Garsiel

    本篇内容为转载,主要用于个人学习使用,作者:Tali Garsiel 一.介绍 浏览器可以被认为是使用最广泛的软件,本文将介绍浏览器的工作原理,我们将看到,从你在地址栏输入google.com到你看到 ...

  8. Ajax工作原理

    在写这篇文章之前,曾经写过一篇关于AJAX技术的随笔,不过涉及到的方面很窄,对AJAX技术的背景.原理.优缺点等各个方面都很少涉及null.这次写这篇文章的背景是因为公司需要对内部程序员做一个培训.项 ...

  9. 一篇笔记整理JVM工作原理

    首先要了解的 >>数据类型 Java虚拟机中,数据类型可以分为两类:基本类型和引用类型. 基本类型的变量保存原始值,即:他代表的值就是数值本身:而引用类型的变量保存引用值.“引用值”代表了 ...

随机推荐

  1. 基于VC的ACM音频编程接口压缩Wave音频(一)

    (一)概述 音频数据一般都具有较高的采样率,经过压缩的原始数据才具有实用价值,否则不仅要占用大量存储空间而且在播放或进行网络传输时效率也是非常低下的,所以音频数字压缩编码在多媒体应用中有着广泛而又重要 ...

  2. CentOS 7 安装 vmware-tools

    [原创]标题:<CentOS 7 安装 vmware-tools>:作者:肖雪峰,QQ:35360657. 用 VMware Workstation 11 新安装了CentOS 7虚拟机, ...

  3. 张洋:浅析PageRank算法

    本文引自http://blog.jobbole.com/23286/ 很早就对Google的PageRank算法很感兴趣,但一直没有深究,只有个轮廓性的概念.前几天趁团队outing的机会,在动车上看 ...

  4. ‘ant-version’不是内部或外部命令,也不是可运行的程序

    下载apache-ant-1.9.2-bin.zip后,解压目录:F:\selenium\apache-ant-1.9.2 配置环境变量,在“我的电脑->属性->高级->环境变量 - ...

  5. 从RAM新建QIcon对象 / Create a QIcon from binary data

    一般,QIcon是通过png或ico等图标文件来初始化的,但是如果图标资源已经在内存里了,或者一个zip压缩文件内,可以通过QPixmap作为桥梁,转换为图标. zf = zipfile.ZipFil ...

  6. docker on centos

    docker最好在centos7上安装,centos6.5上似乎麻烦不少 这里直接在centos7上安装,要提前装一下epel的repo yum install docker 安装就行 chkconf ...

  7. Magicodes.WeiChat——版本发布历史

    购买地址:https://item.taobao.com/item.htm?id=520205558575 您可以在新标签页打开此图,以查看原始图片. Magicodes.WeiChat为湖南心莱信息 ...

  8. 在 Cloud 9 中搭建和运行 Go

    简介 自从使用了Chromebook,我脑中一直充斥着在云端开发的念头.在我使用过的位数不多的在线开发环境中,唯有 Cloud 9令我比较满意.实际上,Cloud 9还不支持Go的开发,因此本文我将教 ...

  9. 用JQuery仿造QQ头像裁剪功能

    最近工作真心忙碌,几乎没时间写博客.今天趁周末来仿一个QQ头像裁剪功能插件.效果如下: 所有文件都可在我的Github上下载,从头到尾从简到繁按步骤一共分了9个HTML文件,每个步骤文件里的注释都写的 ...

  10. Homework 3

    1. 是否需要有代码规范? 这些规范都是官僚制度下产生的浪费大家的编程时间.影响人们开发效率, 浪费时间的东西. (反对) 我是个艺术家,手艺人,我有自己的规范和原则.  (反对) 规范不能强求一律, ...