JUC 之定时器 Timer

1. Timer 类

public class Timer {

    public Timer() {
        this("Timer-" + serialNumber());
    }

    private final TimerThread thread = new TimerThread(queue);
    public Timer(String name) {
        thread.setName(name);
        thread.start();
    }

}

创建 Timer 类时启动了1个新的非守护线程(TimerThread)
这个新启动的线程并不是守护线程,而且一直在运行。
一直在运行的原因是新线程内部有一个死循环,TimerThread.mainLoop()方法

1.1 TimerThread 类

class TimerThread extends Thread {
    boolean newTasksMayBeScheduled = true;

    private void mainLoop() {
        while (true) {
            try {
                TimerTask task;
                boolean taskFired;
                synchronized(queue) {
                    // Wait for queue to become non-empty
                    while (queue.isEmpty() && newTasksMayBeScheduled)
                        queue.wait();
                    if (queue.isEmpty())
                        break; // Queue is empty and will forever remain; die

                    // ...
                    if (!taskFired) // Task hasn't yet fired; wait
                        queue.wait(executionTime - currentTime);
                }
                if (taskFired)  // Task fired; run it, holding no locks
                    task.run();
            } catch(InterruptedException e) {
            }
        }
    }
}

注意变量 newTasksMayBeScheduled

1.2 schedule(TimerTask, delay)

public void schedule(TimerTask task, long delay) {
    if (delay < 0)
        throw new IllegalArgumentException("Negative delay.");
    sched(task, System.currentTimeMillis()+delay, 0);
}

1.3 TimerTask 类

TimerTask 是 abstract class, 执行计划任务由其子类实现

public abstract class TimerTask implements Runnable {
    public abstract void run();
}

2. 定时任务

@Test
public void timerSchedule() throws Exception {
    log.info("开始时间:" + System.currentTimeMillis());

    Timer timer = new Timer();
    timer.schedule(new TimerTask() {
        @Override
        public void run() {
            log.info("任务执行:" + System.currentTimeMillis());
        }
    }, 1000);

    TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
}

打印结果:

15:41:38.062 [main] INFO juc.TimerDemo - 开始时间:1698738098059
15:41:39.070 [Timer-0] INFO juc.TimerDemo - 任务执行:1698738099070

Timer-0 线程执行任务后,还存在

3. 线程销毁

3.1 终止计时器

Timer.cancel() 方法的作用是终止此计时器,丢弃当前所有已安排的任务

public class Timer {
    public void cancel() {
        synchronized(queue) {
            thread.newTasksMayBeScheduled = false;
            queue.clear();
            queue.notify();  // In case queue was already empty.
        }
    }
}

3.2 示例

@Test
public void timerCancel() throws Exception {
    log.info("开始时间:" + System.currentTimeMillis());

    Timer timer = new Timer();
    timer.schedule(new TimerTask() {
        @Override
        public void run() {
            log.info("任务执行:" + System.currentTimeMillis());
        }
    }, 5000);

    TimeUnit.SECONDS.sleep(10);
    timer.cancel();
    TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
}

执行结果:

15:51:06.810 [main] INFO juc.TimerDemo - 开始时间:1698738666808
15:51:11.831 [Timer-0] INFO juc.TimerDemo - 任务执行:1698738671831

查看 Timer-0 线程被销毁

4. 执行多个TimerTask任务

@Test
public void timerTasks() throws Exception {
    log.info("开始时间:" + System.currentTimeMillis());

    Timer timer = new Timer();
    timer.schedule(new TimerTask() {
        @Override
        public void run() {
            log.info("任务执行:" + System.currentTimeMillis());
        }
    }, 1000);

    timer.schedule(new TimerTask() {
        @Override
        public void run() {
            log.info("任务执行:" + System.currentTimeMillis());
        }
    }, 2000);

    TimeUnit.SECONDS.sleep(5);
}

执行结果:

17:49:00.393 [main] INFO juc.TimerDemo - 开始时间:1698745740388
17:49:01.412 [Timer-0] INFO juc.TimerDemo - 任务执行:1698745741412
17:49:02.402 [Timer-0] INFO juc.TimerDemo - 任务执行:1698745742401

5. 延时执行TimerTask

TimerTask 是以队列的方式一个一个被顺序执行的,需等到前一个任务执行完成后才开始下一个任务
原因是创建了1个Timer类导致创建了1个TimerThread线程,1个TimerThread线程管理1个队列,在队列中得按顺序运行任务

@Test
public void delayTimerTask() throws Exception {
    log.info("开始时间:" + System.currentTimeMillis());

    Timer timer = new Timer();
    timer.schedule(new TimerTask() {
        @SneakyThrows
        @Override
        public void run() {
            TimeUnit.SECONDS.sleep(5);
            log.info("任务执行:" + System.currentTimeMillis());
        }
    }, 1000);

    timer.schedule(new TimerTask() {
        @Override
        public void run() {
            log.info("任务执行:" + System.currentTimeMillis());
        }
    }, 2000);

    TimeUnit.SECONDS.sleep(10);
}

打印结果:

17:54:07.700 [main] INFO juc.TimerDemo - 开始时间:1698746047698
17:54:13.727 [Timer-0] INFO juc.TimerDemo - 任务执行:1698746053727
17:54:13.728 [Timer-0] INFO juc.TimerDemo - 任务执行:1698746053728
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容