多线程案例(三):定时器

21 篇文章 0 订阅
12 篇文章 0 订阅

1 定时器简介

 定时器是多线程编码中的一个重要组件,它就好比一个闹钟,例如我们想去坐车,但是不想现在去坐车,想8:30去坐车,于是我们订了一个8点钟的闹钟,也就是说定时器有一些逻辑,但并不想立即执行,而是要等一定的时间之后再来执行.
 使用场景:浏览器访问服务器的时候就会使用定时器来判定是否超时, 标准库中其实已经提供了阻塞队列,定时器等基本组件,实际工作中我们直接使用标准库的就可以,下面的代码主要是为了理解其原理,加深对多线程的理解.

2 构成

  • 使用一个Task类来描述"一段逻辑",也可以说一个要执行的任务,同时也要记住这个任务在什么时候开始执行;
  • 使用一个阻塞优先队列来组织若干个Task;

 这个阻塞优先队列既支持阻塞的特性,又支持按优先级的"先进先出" ,使用优先级队列的目的是为了保证队首元素就是那个最早要被执行的任务,本质上就是一个堆.判断当前队列中是否有任务时间到了,只需要判断队首元素是否到时间即可.

定时器四部分:
 a) Task类来描述任务
在这里插入图片描述

Runnable 中有一个 run 方法,就可以借助这个 run 方法来描述要执行的具体的任务是啥, time 表示什么时候开始执行 command
,是一个绝对时间(ms级别的时间戳).

 b) 阻塞优先队列组织这些任务
在这里插入图片描述
 c) 扫描线程,定时扫描队首元素
在这里插入图片描述

 d) 接口,让调用者能安排任务给定时器
在这里插入图片描述

 代码截止到这里还有一个比较严重的问题,就是在扫描线程的时候,可能会出现忙等的现象,就例如我们订了一个8:30的闹钟,然后再八点的时候就开始每隔1秒钟就看一下时间,这就是所谓的"忙等"现象.
 解决方式:wait,notify方法,wait(time)会有一个时间上限,代码阻塞到wait处,避免了频繁占用CPU,解决了忙等的问题,如下所示.
在这里插入图片描述

3 执行流程图

在这里插入图片描述

4 源码

package ThreadDemo;

import java.util.concurrent.PriorityBlockingQueue;

/**
 * Created with IntelliJ IDEA
 * Description:
 * 定时器
 * @author :Lee
 * @description:TODO
 * @date :Created in 2022/2/21 13:13
 */
public class Time {
    static class Task implements Comparable<Task> {
        private Runnable command;
        private long time;

        public Task(Runnable command, long after) {
            this.command = command;
            this.time = System.currentTimeMillis() + after;
        }

        public void run() {
            command.run();
        }
        @Override
        public int compareTo(Task o) {
            return (int) (this.time - o.time);
        }
    }
    static class Worker extends Thread {
        private Object mailBox = null;

        private PriorityBlockingQueue<Task> queue = null;

        public Worker (PriorityBlockingQueue<Task> queue, Object mailBox) {
            this.queue = queue;
            this.mailBox = mailBox;
        }

        @Override
        public void run() {
            while (true) {
                try {
                    Task task = queue.take();
                    long curTime = System.currentTimeMillis();
                    if(task.time > curTime) {
                        queue.put(task);
                        synchronized (mailBox) {
                            mailBox.wait(task.time - curTime);
                        }
                    } else {
                        task.run();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    break;
                }
            }
        }
    }
    static class Timer {
        private Object mailBox = new Object();
        private PriorityBlockingQueue<Task> queue = new PriorityBlockingQueue<>();

        public Timer() {
            Worker worker = new Worker(queue,mailBox);
            worker.start();
        }

        public void schedule (Runnable command, long after) {
            Task task = new Task(command,after);
            queue.put(task);
            synchronized (mailBox) {
                mailBox.notify();
            }
        }
    }

    public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("上岸!");
                timer.schedule(this,2000);
            }
        },2000);
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值