JavaSE 多线程——定时器

本文介绍了JavaSE中的定时器Timer及其使用方式,包括无参和有参构造方法,以及如何创建和调度TimerTask。讨论了Timer的优缺点,如线程安全但不支持并发,可能导致内存泄漏。还详细解析了schedule和scheduleAtFixedRate方法的使用场景和执行策略。
摘要由CSDN通过智能技术生成

一、定时器概述

  • 间隔特定的时间,执行特定的程序

二、定时器的实现方式

  1. 使用sleep() 方法,设置睡眠时间,在某个时间点唤醒相关执行(相当于原始定时器,不怎么用)
  2. Java中的类库:java.util.Timer,用于Java线程里指定时间或周期运行任务,Timer是线程安全的,但不提供实时性(real-time)保证,使用也不多,因为现在高级框架都是支持定时任务的。TimerTask把我们的业务逻辑写好之后,使用Timer定时执行即可
  3. 使用框架,目前使用较多的是Spring中提供的SpringTask框架,通过简单的配置就可以完成定时任务,但底层也是基于Timer来实现的

三、Timer

  • Timer 可以按计划执行重复的任务或者定时执行指定任务,这是因为 Timer 内部利用了一个后台线程 TimerThread 有计划地执行指定任务,即对于每一个 Timer 对象而言,其内部都是对应着单个后台线程,这个线程用于顺序执行优先队列中所有的计时器任务
  • Timer是一个实用工具类,该类用来调度一个线程,使它可以在将来某一时刻执行,Java 的 Timer 类可以调度一个任务运行一次或定期循环运行,另外定时器中的操作要尽可能花费短的时间
  • Timer 劣势:
    Timer 是基于绝对时间的,对系统时间比较敏感
    Timer 内部是单一线程,不支持多个任务并发执行
    Timer 运行多个 TimeTask 时,只要其中之一抛出异常,其它任务便会自动终止运行
    Timer 不明确任务实际执行策略,不方便自行控制
    Timer 存在潜在内存泄漏问题,因为默认 Timer 执行线程不是 daemon 线程, 任务执行完,主线程(或其他启动定时器的线程)结束时,task 线程并没有结束

1. 构造方法

1.1 无参构造方法

  • 创建一个无参定时器对象
public Timer() {
    this("Timer-" + serialNumber());
}

1.2 有参构造方法

  • 创建一个可以指定相关线程作为守护线程运行的定时器对象
public Timer(boolean isDaemon) {
        this("Timer-" + serialNumber(), isDaemon);
    }
  • 创建一个指定名称的定时器对象
public Timer(String name) {
        thread.setName(name);
        thread.start();
    }
  • 创建一个指定名称,相关线程作为守护线程运行的定时器对象
public Timer(String name, boolean isDaemon) {
    thread.setName(name);
    thread.setDaemon(isDaemon);
    thread.start();
}

四、TimerTask

  • TimerTask是一个抽象类,实现了 Runnable 接口,代表一个可被执行的任务,我们需要扩展该类以便创建自己的TimerTask,这个TimerTask可以被Timer调度
  • Timer计划的任务被TimerTask封装,通过继承TimerTask类并实现 run() 方法来自定义要执行的任务,即TimerTask把我们得业务逻辑写好之后,使用Timer定时执行
  • 步骤:
    创建一个Timer
    创建一个TimerTask
    使用Timer执行TimerTask

五、schdule

  • Timer的定时调度函数
  1. 安排在指定延迟后执行指定的任务(以当前时间为基准,延迟指定的毫秒后执行一次task任务)
public void schedule(TimerTask task, long delay) {
    if (delay < 0)
        throw new IllegalArgumentException("Negative delay.");
    sched(task, System.currentTimeMillis()+delay, 0);
}
  1. 安排在指定的时间执行指定的任务(在指定的日期执行一次task任务,如果日期time早于当前时间,则立刻执行)
public void schedule(TimerTask task, Date time) {
    sched(task, time.getTime(), 0);
}
  1. 安排指定的任务从指定的延迟后开始进行重复固定延迟执行TimerTask任务(指定任务task在指定延迟delay后进行固定频率peroid的执行)
public void schedule(TimerTask task, long delay, long period) {
    if (delay < 0)
        throw new IllegalArgumentException("Negative delay.");
    if (period <= 0)
        throw new IllegalArgumentException("Non-positive period.");
    sched(task, System.currentTimeMillis()+delay, -period);
}
  1. 安排指定的任务在指定的时间开始进行重复的固定延迟执行(指定的任务task在指定的时间firstTime开始进行重复的固定速率period执行)
public void schedule(TimerTask task, Date firstTime, long period) {
    if (period <= 0)
        throw new IllegalArgumentException("Non-positive period.");
    sched(task, firstTime.getTime(), -period);
}

六、scheduleAtFixedRate

  • Timer的定时调度函数
  1. 安排指定的任务在指定的延迟后开始进行重复的固定速率执行(以当前时间为基准,延迟指定的毫秒后,再按指定的时间间隔周期性地无限次数的执行TimerTask任务,如果日期firstTime早于当前时间,则立刻执行,且不执行在时间差内的任务)
public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
    if (delay < 0)
        throw new IllegalArgumentException("Negative delay.");
    if (period <= 0)
        throw new IllegalArgumentException("Non-positive period.");
    sched(task, System.currentTimeMillis()+delay, period);
}
  1. 安排指定的任务在指定的时间开始进行重复的固定速率执行(在指定的日期之后,按指定的时间间隔周期性地无限次数的执行TimerTask任务,如果日期firstTime早于当前时间,则立即执行,并补充性的执行在时间差内的任务)
public void scheduleAtFixedRate(TimerTask task, Date firstTime, long period) {
    if (period <= 0)
        throw new IllegalArgumentException("Non-positive period.");
    sched(task, firstTime.getTime(), period);
}

七、测试用例

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class TimerTest {
	public static void main(String[] args) {
		/**
		 * 使用定时器指定定时任务
		 */
		// 创建定时器对象
		Timer timer = new Timer();
		// Timer timer = new Timer(true); //守护线程的方式

		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date firstTime;
		try {
			firstTime = sdf.parse("2020-09-09 15:55:50");
			// 指定定时任务
			// timer.scheduleAtFixedRate(task, firstTime, period);
			// timer.schedule(定时任务, 第一次执行时间, 间隔多久执行一次);
			timer.scheduleAtFixedRate(new MyTimerTask(), firstTime, 1000 * 10);
		} catch (ParseException e) {
			e.printStackTrace();
		}

		// 匿名内部类方式
//		timer.schedule(new TimerTask() {
//			@Override
//			public void run() {
//				// 业务逻辑
//			}
//		}, firstTime, 1000 * 10);
	}
}

// 定时任务类
class MyTimerTask extends TimerTask {

	@Override
	public void run() {
		// 编写执行任务
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String strTime = sdf.format(new Date());
		System.out.println(strTime + "完成任务");
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jayco江柯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值