Java【多线程】(6)定时器


目录

1.前言

2.正文

2.1库中定时器

2.2手搓定时器

3.小结


1.前言

哈喽大家好呀,今天继续给大家分享Java中定时器的学习,正文包括定时器的三种实现方式,正文如下。

2.正文

在 Java 中,定时器(Timer)是一种用于在指定时间或周期性地执行任务的工具。Java 提供了多种定时器实现方式,包括 TimerTimerTaskScheduledExecutorService。

2.1库中定时器

最基础版的实现方式:

public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("hello 3000");
            }
        }, 3000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("hello 1000");
            }
        }, 1000);
    }

执行流程

  1. 创建Timer实例

    • Timer timer = new Timer() 创建一个新的定时器

    • Timer内部会启动一个后台线程(非守护线程)来执行定时任务

  2. 调度第一个任务

    • 延迟3000毫秒后执行,输出"hello 3000"

    • 任务被封装为TimerTask对象

  3. 调度第二个任务

    • 延迟1000毫秒后执行,输出"hello 1000"

    • 虽然代码中先注册了3000ms的任务,但实际会先执行1000ms的任务


关键特性

  1. 执行顺序

    • Timer内部维护了一个任务队列,按执行时间排序

    • 即使先注册长时间延迟的任务,短延迟的任务也会优先执行

  2. 单线程执行

    • 所有任务都在同一个线程中顺序执行

    • 如果一个任务执行时间过长,会影响后续任务的准时执行

  3. 非守护线程

    • Timer创建的线程是非守护线程

    • 即使main方法结束,Timer线程仍会继续运行,直到所有任务完成

进阶版利用线程池实现定时器: 

public static void main(String[] args) {
    // 1. 创建线程池大小为3的定时任务执行器
    ScheduledExecutorService executor = Executors.newScheduledThreadPool(3);
    
    // 2. 定义要执行的任务(Lambda表达式实现Runnable接口)
    Runnable task = () -> {
        System.out.println(Thread.currentThread().getName());
    };
    
    // 3. 以固定速率调度任务
    executor.scheduleAtFixedRate(task, 1, 3, TimeUnit.SECONDS);
}

核心组件详解


1. ScheduledExecutorService

  • 功能:Java 5引入的定时任务接口,比传统Timer更强大

  • 优势

    • 基于线程池,支持多任务并发执行

    • 提供更灵活的调度方式

    • 更好的异常处理机制

2. Executors.newScheduledThreadPool(3)

  • 创建包含3个线程的定时任务线程池

  • 线程池参数说明:

    • 核心线程数=3(本例中)

    • 适合执行大量短期定时任务

    • 线程可重复利用,避免频繁创建销毁开销

3. scheduleAtFixedRate方法

方法签名:

ScheduledFuture<?> scheduleAtFixedRate(
    Runnable command,
    long initialDelay,
    long period,
    TimeUnit unit
)

 参数说明:

  1. command:要执行的任务(Runnable实现)

  2. initialDelay:首次执行的延迟时间

  3. period:连续执行之间的周期

  4. unit:时间单位(本例为秒)


执行流程分析

  1. 初始化阶段

    • 创建包含3个工作线程的线程池

    • 定义打印当前线程名的任务

  2. 任务调度

    • 1秒后首次执行任务

    • 之后每3秒固定执行一次

    • 执行线程可能不同(由线程池分配)

  3. 输出示例

    pool-1-thread-1
    pool-1-thread-2
    pool-1-thread-3
    pool-1-thread-1
    ...

2.2手搓定时器

分为三个类:任务类,定时器类,测试类最后附上总代码:

/**
 * 自定义定时任务类,实现了Comparable接口用于优先级队列排序
 */
class MyTimerTask implements Comparable<MyTimerTask> {
    private Runnable task;  // 实际要执行的任务
    private long time;      // 任务执行的时间戳(毫秒)

    /**
     * 构造函数
     * @param task 要执行的任务
     * @param delay 延迟时间(毫秒)
     */
    public MyTimerTask(Runnable task, long delay) {
        this.task = task;
        this.time = System.currentTimeMillis() + delay; // 计算绝对执行时间
    }

    /**
     * 实现Comparable接口,用于优先级队列排序
     * @param o 另一个定时任务
     * @return 比较结果
     */
    @Override
    public int compareTo(MyTimerTask o) {
        return (int) (this.time - o.time); // 按执行时间排序
    }

    /**
     * 获取任务执行时间
     * @return 执行时间戳
     */
    public long getTime() {
        return this.time;
    }

    /**
     * 执行任务
     */
    public void run() {
        task.run(); // 委托给实际的Runnable执行
    }
}
/**
 * 自定义定时器实现
 */
class MyTimer {
    // 优先级队列,按执行时间排序,保证最早执行的任务在队首
    private PriorityQueue<MyTimerTask> queue = new PriorityQueue<>();
    
    // 用于线程同步的锁对象
    private Object locker = new Object();

    /**
     * 调度任务方法
     * @param task 要执行的任务
     * @param delay 延迟时间(毫秒)
     */
    public void schedule(Runnable task, long delay) {
        synchronized (locker) {
            // 创建定时任务并加入队列
            MyTimerTask myTimerTask = new MyTimerTask(task, delay);
            queue.offer(myTimerTask);
            
            // 通知工作线程有新任务加入
            locker.notify();
        }
    }

    /**
     * 定时器构造函数
     */
    public MyTimer() {
        // 创建工作线程
        Thread t = new Thread(() -> {
            try {
                while (true) {  // 无限循环处理任务
                    synchronized (locker) {
                        // 队列为空时等待
                        while (queue.isEmpty()) {
                            locker.wait();
                        }
                        
                        // 获取但不移除队首任务
                        MyTimerTask task = queue.peek();
                        long currentTime = System.currentTimeMillis();
                        
                        if (currentTime < task.getTime()) {
                            // 还未到执行时间,等待剩余时间
                            locker.wait(task.getTime() - currentTime);
                        } else {
                            // 执行任务并从队列移除
                            task.run();
                            queue.poll();
                        }
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        t.start();  // 启动工作线程
    }
}
/**
 * 定时器测试类
 */
public class demoTime {
    public static void main(String[] args) {
        MyTimer timer = new MyTimer();  // 创建定时器
        
        // 添加3个定时任务
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello 3000");
            }
        }, 3000);  // 3秒后执行
        
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello 2000");
            }
        }, 2000);  // 2秒后执行
        
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello 1000");
            }
        }, 1000);  // 1秒后执行
    }
}
import java.util.PriorityQueue;

class MyTimerTask implements Comparable<MyTimerTask>{
    private Runnable task;
    private long time;

    public MyTimerTask(Runnable task, long time) {
        this.task = task;
        this.time = time;
    }

    @Override
    public int compareTo(MyTimerTask o) {
        return (int) (this.time - o.time);
    }

    public long getTime(){
        return this.time;
    }

    public void run(){
        task.run();
    }
}

class MyTimer{
    private PriorityQueue <MyTimerTask> queue = new PriorityQueue<>();
    private Object locker = new Object();

    public void schedule(Runnable task,long delay){
        synchronized (locker){
            MyTimerTask myTimerTask = new MyTimerTask(task,System.currentTimeMillis() + delay);
            queue.offer(myTimerTask);
            locker.notify();
        }
    }

    public MyTimer(){
        Thread t = new Thread(()-> {
            try {
                while (true) {
                    synchronized (locker) {
                        while (queue.isEmpty()) {
                            locker.wait();
                        }
                        MyTimerTask task = queue.peek();
                        if (System.currentTimeMillis() < task.getTime()) {
                            locker.wait(task.getTime() - System.currentTimeMillis());
                        } else {
                            task.run();
                            queue.poll();
                        }
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        t.start();
    }
}

public class demoTime {
    public static void main(String[] args) {
        MyTimer timer = new MyTimer();
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello 3000");
            }
        }, 3000);
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello 2000");
            }
        }, 2000);
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello 1000");
            }
        }, 1000);
    }
}

3.小结

今天的分享到这里就结束了,喜欢的小伙伴点点赞点点关注,你的支持就是对我最大的鼓励,大家加油!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

爱吃烤鸡翅的酸菜鱼

希望大家对我多多支持喔~

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

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

打赏作者

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

抵扣说明:

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

余额充值