Java 定时器的多种实现方式
作者:卷卷啊 发布时间:2021-06-14 03:15:09
目录
一、前言
(1)Timer
(2)DelayedQueue 延迟队列
(3)ScheduledThreadPoolExecutor
(4)ScheduledThreadPoolExecutor
一、前言
定时器有三种表现形式:
按固定周期定时执行
延迟一定时间后执行
指定某个时刻执行
JDK 提供了三种常用的定时器实现方式,分别为:
Timer
DelayedQueue
延迟队列ScheduledThreadPoolExecutor
(1)Timer
发现 eureka
中大量使用了 Timer
定时器:
Timer 属于 JDK 比较早期版本的实现,它可以实现固定周期的任务,以及延迟任务。
Timer 会起动一个异步线程去执行到期的任务,任务可以只被调度执行一次,也可以周期性反复执行多次。
Timer 是如何使用的,示例代码如下:
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
// 业务代码
}
}, 5000, 5000); // 5s 后调度一个周期为 5s 的定时任务
TimerTask
是实现了Runnable
接口的抽象类Timer
负责调度和执行TimerTask
Timer
的内部构造,如下:
public class Timer {
// 小根堆,run操作 O(1)、新增 O(logn)、cancel O(logn)
private final TaskQueue queue = new TaskQueue();
// 创建另外线程,任务处理,会轮询 queue
private final TimerThread thread = new TimerThread(queue);
public Timer(String name) {
thread.setName(name);
thread.start();
}
}
Timer
它是存在不少设计缺陷的,所以并不推荐用户使用:
Timer
是单线程模式,如果某个TimerTask
执行时间很久,会影响其他任务的调度。Timer
的任务调度是基于系统绝对时间的,如果系统时间不正确,可能会出现问题。TimerTask
如果执行出现异常,Timer
并不会捕获,会导致线程终止,其他任务永远不会执行。
(2)DelayedQueue 延迟队列
特征如下:
DelayedQueue
是 JDK 中一种可以延迟获取对象的阻塞队列,其内部是采用优先级队列PriorityQueue
存储对象DelayQueue
中的每个对象都必须实现Delayed
接口,并重写compareTo
和getDelay
方法
DelayedQueue
的使用方法如下:
public class DelayQueueTest {
public static void main(String[] args) throws Exception {
BlockingQueue<SampleTask> delayQueue = new DelayQueue<>();
long now = System.currentTimeMillis();
delayQueue.put(new SampleTask(now + 1000));
delayQueue.put(new SampleTask(now + 2000));
delayQueue.put(new SampleTask(now + 3000));
for (int i = 0; i < 3; i++) {
System.out.println(new Date(delayQueue.take().getTime()));
}
}
static class SampleTask implements Delayed {
long time;
public SampleTask(long time) {
this.time = time;
}
public long getTime() {
return time;
}
@Override
public int compareTo(Delayed o) {
return Long.compare(this.getDelay(TimeUnit.MILLISECONDS), o.getDelay(TimeUnit.MILLISECONDS));
}
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(time - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}
}
}
(3)ScheduledThreadPoolExecutor
JDK
提供了功能更加丰富的 ScheduledThreadPoolExecutor
public class ScheduledExecutorServiceTest {
public static void main(String[] args) {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(5);
executor.scheduleAtFixedRate(() -> System.out.println("Hello World"), 1000, 2000, TimeUnit.MILLISECONDS); // 1s 延迟后开始执行任务,每 2s 重复执行一次
}
}
ScheduledThreadPoolExecutor
使用了阻塞队列 DelayedWorkQueue
。
(4)ScheduledThreadPoolExecutor
线程应该是最常见的实现方案,创建一个线程执行任务即可,举例几个不同的写法,代码如下
4.1.使用thread + runnable
package com.yezi_tool.demo_basic.test;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class ThreadTest {
private Integer count = 0;
public ThreadTest() {
test1();
}
public void test1() {
new Thread(() -> {
while (count < 10) {
System.out.println(new Date().toString() + ": " + count);
count++;
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
4.2.使用线程池 + runnable
package com.yezi_tool.demo_basic.test;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Component
public class ThreadTest {
private static final ExecutorService threadPool = Executors.newFixedThreadPool(5);// 线程池
private Integer count = 0;
public ThreadTest() {
test2();
}
public void test2() {
threadPool.execute(() -> {
while (count < 10) {
System.out.println(new Date().toString() + ": " + count);
count++;
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
来源:https://juejin.cn/post/6970339917700268040


猜你喜欢
- 本文实例为大家分享了java实现图片角度旋转并获得图片信息的具体代码,供大家参考,具体内容如下public class Demo {/**
- DSLDomain-specific language: 一种专注于某一领域,仅针对部分表达方式的计算机编程语言。特点方法链 Method
- 为什么要重复造轮子你可能会问,Spring已经自带了全局异常拦截,为什么还要重复造轮子呢?这是个好问题,我觉得有以下几个原因装逼Spring
- 前言A*搜寻算法俗称A星算法。这是一种在图形平面上,有多个节点的路径,求出最低通过成本的算法。常用于游戏中通过二维数组构建的一个迷宫,“%”
- C#自己没有Inputbox这个类,但是Inputbox也蛮好用的,所以有两种方法可以使用一:间接调用vb中的Inputbox功能 
- 1.1 概述分布式系统:分布式系统指由很多台计算机组成的一个整体!这个整体一致对外,并且处理同一请求!系统对内透明,对外不透明!内部的每台计
- 本文实例讲述了Android中使用Service实现后台发送邮件功能。分享给大家供大家参考,具体如下:程序如下:import android
- 前言 短时间提升自己最快的手段就是背面试题,最近总结了Java常用的面试题,分享给大家,希望大家都能圆梦大厂,加油,我命由我不由天
- 一.服务器端获取Session对象依赖于客户端携带的Cookie中的JSESSIONID数据。如果用户把浏览器的隐私级别调到最高,这时浏览器
- 本文为大家分享了Android网络连接判断与相关处理,供大家参考,具体内容如下获取网络信息需要在AndroidManifest.xml文件中
- 拖曳小球WPF的拖曳效果,基本配置一下,就可以了,但是自绘的话,就得自己控制,按键点击,按键移动和按键松开的事件,与其配合达到目的。这个效果
- 本文实例讲述了Android编程设计模式之中介者模式。分享给大家供大家参考,具体如下:一、介绍中介者模式(Mediator Pattern)
- BroadcastReceiver(广播 * ),在Android开发中,BroadcastReceiver的应用场景非常多,属于Andro
- 树概念及结构树是一种 非线性 的数据结构,它是由 n ( n>=0 )个有限结点组成一个具有层次关系的集合把它叫做树是因 为它看起来像
- 首先,确保 IDEA 软件正确安装完成,Java 开发工具包 JDK 安装完成。IDEA 的 Java 项目 (Project) 则相当于
- 本文所述为一个Android上传文件的源代码,每一步实现过程都备有详尽的注释,思路比较清楚,学习了本例所述上传文件代码之后,你可以应对其它格
- 1. Spring 是什么我们通常所说的 Spring 指的是 Spring Framework(Spring 框架),它是一个开源框架,有
- 前言面对众多卡片层叠效果,我们的产品童鞋也突发奇想,搞出了另一种卡片层叠切换展示的交互,而且产品狗们居然要求多做几种动效给他们看,好让他们选
- IntelliJ IDEA是广受Java开发者喜爱的工具,其商业版的价格十分昂贵,如下图:现在有机会免费获取IntelliJ IDEA的正版
- 本文实例讲述了C#基于正则表达式删除字符串中数字或非数字的方法。分享给大家供大家参考,具体如下:/// 去掉字符串中的数字public st