【高并发】ScheduledThreadPoolExecutor与Timer的区别和简单示例

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: JDK 1.5开始提供ScheduledThreadPoolExecutor类,ScheduledThreadPoolExecutor类继承ThreadPoolExecutor类重用线程池实现了任务的周期性调度功能。在JDK 1.5之前,实现任务的周期性调度主要使用的是Timer类和TimerTask类。本文,就简单介绍下ScheduledThreadPoolExecutor类与Timer类的区别,ScheduledThreadPoolExecutor类相比于Timer类来说,究竟有哪些优势,以及二者分别实现任务调度的简单示例。

大家好,我是冰河~~

JDK 1.5开始提供ScheduledThreadPoolExecutor类,ScheduledThreadPoolExecutor类继承ThreadPoolExecutor类重用线程池实现了任务的周期性调度功能。在JDK 1.5之前,实现任务的周期性调度主要使用的是Timer类和TimerTask类。本文,就简单介绍下ScheduledThreadPoolExecutor类与Timer类的区别,ScheduledThreadPoolExecutor类相比于Timer类来说,究竟有哪些优势,以及二者分别实现任务调度的简单示例。

二者的区别

线程角度

  • Timer是单线程模式,如果某个TimerTask任务的执行时间比较久,会影响到其他任务的调度执行。
  • ScheduledThreadPoolExecutor是多线程模式,并且重用线程池,某个ScheduledFutureTask任务执行的时间比较久,不会影响到其他任务的调度执行。

系统时间敏感度

  • Timer调度是基于操作系统的绝对时间的,对操作系统的时间敏感,一旦操作系统的时间改变,则Timer的调度不再精确。
  • ScheduledThreadPoolExecutor调度是基于相对时间的,不受操作系统时间改变的影响。

是否捕获异常

  • Timer不会捕获TimerTask抛出的异常,加上Timer又是单线程的。一旦某个调度任务出现异常,则整个线程就会终止,其他需要调度的任务也不再执行。
  • ScheduledThreadPoolExecutor基于线程池来实现调度功能,某个任务抛出异常后,其他任务仍能正常执行。

任务是否具备优先级

  • Timer中执行的TimerTask任务整体上没有优先级的概念,只是按照系统的绝对时间来执行任务。
  • ScheduledThreadPoolExecutor中执行的ScheduledFutureTask类实现了java.lang.Comparable接口和java.util.concurrent.Delayed接口,这也就说明了ScheduledFutureTask类中实现了两个非常重要的方法,一个是java.lang.Comparable接口的compareTo方法,一个是java.util.concurrent.Delayed接口的getDelay方法。在ScheduledFutureTask类中compareTo方法方法实现了任务的比较,距离下次执行的时间间隔短的任务会排在前面,也就是说,距离下次执行的时间间隔短的任务的优先级比较高。而getDelay方法则能够返回距离下次任务执行的时间间隔。

是否支持对任务排序

  • Timer不支持对任务的排序。
  • ScheduledThreadPoolExecutor类中定义了一个静态内部类DelayedWorkQueue,DelayedWorkQueue类本质上是一个有序队列,为需要调度的每个任务按照距离下次执行时间间隔的大小来排序

能否获取返回的结果

  • Timer中执行的TimerTask类只是实现了java.lang.Runnable接口,无法从TimerTask中获取返回的结果。
  • ScheduledThreadPoolExecutor中执行的ScheduledFutureTask类继承了FutureTask类,能够通过Future来获取返回的结果。

通过以上对ScheduledThreadPoolExecutor类和Timer类的分析对比,相信在JDK 1.5之后,就没有使用Timer来实现定时任务调度的必要了。

二者简单的示例

这里,给出使用Timer和ScheduledThreadPoolExecutor实现定时调度的简单示例,为了简便,我这里就直接使用匿名内部类的形式来提交任务。

Timer类简单示例

源代码示例如下所示。

package io.binghe.concurrent.lab09;

import java.util.Timer;
import java.util.TimerTask;

/**
 * @author binghe
 * @version 1.0.0
 * @description 测试Timer
 */
public class TimerTest {

    public static void main(String[] args) throws InterruptedException {
        Timer timer = new Timer();
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                System.out.println("测试Timer类");
            }
        }, 1000, 1000);
        Thread.sleep(10000);
        timer.cancel();
    }
}

运行结果如下所示。

测试Timer类
测试Timer类
测试Timer类
测试Timer类
测试Timer类
测试Timer类
测试Timer类
测试Timer类
测试Timer类
测试Timer类

ScheduledThreadPoolExecutor类简单示例

源代码示例如下所示。

package io.binghe.concurrent.lab09;

import java.util.concurrent.*;

/**
 * @author binghe
 * @version 1.0.0
 * @description 测试ScheduledThreadPoolExecutor
 */
public class ScheduledThreadPoolExecutorTest {
    public static void main(String[] args) throws  InterruptedException {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
        scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println("测试测试ScheduledThreadPoolExecutor");
            }
        }, 1, 1, TimeUnit.SECONDS);

        //主线程休眠10秒
        Thread.sleep(10000);

        System.out.println("正在关闭线程池...");
        // 关闭线程池
        scheduledExecutorService.shutdown();
        boolean isClosed;
        // 等待线程池终止
        do {
            isClosed = scheduledExecutorService.awaitTermination(1, TimeUnit.DAYS);
            System.out.println("正在等待线程池中的任务执行完成");
        } while(!isClosed);

        System.out.println("所有线程执行结束,线程池关闭");
    }
}

运行结果如下所示。

测试测试ScheduledThreadPoolExecutor
测试测试ScheduledThreadPoolExecutor
测试测试ScheduledThreadPoolExecutor
测试测试ScheduledThreadPoolExecutor
测试测试ScheduledThreadPoolExecutor
测试测试ScheduledThreadPoolExecutor
测试测试ScheduledThreadPoolExecutor
测试测试ScheduledThreadPoolExecutor
测试测试ScheduledThreadPoolExecutor
正在关闭线程池...
测试测试ScheduledThreadPoolExecutor
正在等待线程池中的任务执行完成
所有线程执行结束,线程池关闭

注意:关于Timer和ScheduledThreadPoolExecutor还有其他的使用方法,这里,我就简单列出以上两个使用示例,更多的使用方法大家可以自行实现。

推荐阅读

注意:线程的执行顺序与你想的并不一样!!

深入解析Callable接口

两种异步模型与深度解析Future接口!

解密SimpleDateFormat类的线程安全问题和六种解决方案!

不得不说的线程池与ThreadPoolExecutor类浅析

深度解析线程池中那些重要的顶层接口和抽象类

从源码角度分析创建线程池究竟有哪些方式

通过源码深度解析ThreadPoolExecutor类是如何保证线程池正确运行的

通过ThreadPoolExecutor类的源码深度解析线程池执行任务的核心流程

通过源码深度分析线程池中Worker线程的执行流程

从源码角度深度解析线程池是如何实现优雅退出的

好了,今天就到这儿吧,我是冰河,我们下期见~~

目录
相关文章
高并发编程-深入分析wait和sleep的区别并结合源码示例佐证
高并发编程-深入分析wait和sleep的区别并结合源码示例佐证
117 0
|
Java 调度
【高并发】深度解析ScheduledThreadPoolExecutor类的源代码
在【高并发专题】的专栏中,我们深度分析了ThreadPoolExecutor类的源代码,而ScheduledThreadPoolExecutor类是ThreadPoolExecutor类的子类。今天我们就来一起手撕ScheduledThreadPoolExecutor类的源代码。
331 0
【高并发】深度解析ScheduledThreadPoolExecutor类的源代码
|
Java 调度
高并发之——深度解析ScheduledThreadPoolExecutor类的源代码
在【高并发专题】的专栏中,我们深度分析了ThreadPoolExecutor类的源代码,而ScheduledThreadPoolExecutor类是ThreadPoolExecutor类的子类。今天我们就来一起手撕ScheduledThreadPoolExecutor类的源代码。
247 0
|
Java 调度
高并发之——ScheduledThreadPoolExecutor与Timer的区别和简单示例
DK 1.5开始提供ScheduledThreadPoolExecutor类,ScheduledThreadPoolExecutor类继承ThreadPoolExecutor类重用线程池实现了任务的周期性调度功能。在JDK 1.5之前,实现任务的周期性调度主要使用的是Timer类和TimerTask类。本文,就简单介绍下ScheduledThreadPoolExecutor类与Timer类的区别,ScheduledThreadPoolExecutor类相比于Timer类来说,究竟有哪些优势,以及二者分别实现任务调度的简单示例。
192 0
|
7月前
|
消息中间件 Java Linux
2024年最全BATJ真题突击:Java基础+JVM+分布式高并发+网络编程+Linux(1),2024年最新意外的惊喜
2024年最全BATJ真题突击:Java基础+JVM+分布式高并发+网络编程+Linux(1),2024年最新意外的惊喜
|
6月前
|
缓存 NoSQL Java
Java高并发实战:利用线程池和Redis实现高效数据入库
Java高并发实战:利用线程池和Redis实现高效数据入库
519 0
|
4月前
|
监控 算法 Java
企业应用面临高并发等挑战,优化Java后台系统性能至关重要
随着互联网技术的发展,企业应用面临高并发等挑战,优化Java后台系统性能至关重要。本文提供三大技巧:1)优化JVM,如选用合适版本(如OpenJDK 11)、调整参数(如使用G1垃圾收集器)及监控性能;2)优化代码与算法,减少对象创建、合理使用集合及采用高效算法(如快速排序);3)数据库优化,包括索引、查询及分页策略改进,全面提升系统效能。
54 0
|
6月前
|
存储 NoSQL Java
探索Java分布式锁:在高并发环境下的同步访问实现与优化
【6月更文挑战第30天】Java分布式锁在高并发下确保数据一致性,通过Redis的SETNX、ZooKeeper的临时节点、数据库操作等方式实现。优化策略包括锁超时重试、续期、公平性及性能提升,关键在于平衡同步与效率,适应大规模分布式系统的需求。
197 1
|
5月前
|
算法 Java 调度
高并发架构设计三大利器:缓存、限流和降级问题之使用Java代码实现令牌桶算法问题如何解决
高并发架构设计三大利器:缓存、限流和降级问题之使用Java代码实现令牌桶算法问题如何解决
|
5月前
|
监控 网络协议 Java
Java面试题:解释Java NIO与BIO的区别,以及NIO的优势和应用场景。如何在高并发应用中实现NIO?
Java面试题:解释Java NIO与BIO的区别,以及NIO的优势和应用场景。如何在高并发应用中实现NIO?
83 0