【多线程案例】定时器应用及实现

news2024/11/27 8:26:29

文章目录

    • 1. 定时器是什么?
    • 2. 定时器的应用
    • 3. 自己实现定时器

1. 定时器是什么?

定时器就类似生活中的闹钟,它是软件开发中的一个重要组件。当有些线程我们并不希望它立刻执行,这个时候我们就可以使用定时器,规定线程在多长时间后执行。
定时器

2. 定时器的应用

定时器在Java标准库中提供的有一个Timer类。Timer中核心的方法是schedule,schedule中有俩个参数,一个是参数是执行任务代码,另一个参数是指定代码多少毫秒后执行。

public class Test {
    public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("3秒!");
            }
        },3000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("2秒");
            }
        },2000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("1秒");
            }
        },1000);
        System.out.println("开始");

    }
}

运行结果:
111

3. 自己实现定时器

自己实现一个定时器能够帮助我们更好的理解定时器。实现定时器之前我们要知道定时器的构成。

  1. 一个带优先级的堵塞队列;(后面说为什么使用优先级堵塞队列)
  2. 队列中元素都是一个个要执行的任务;
  3. 队列属性要带有时间属性;
  4. 同时有个线程不停扫描队列元素,找到要执行的任务。

为什么使用优先级堵塞队列?
如果使用普通队列:在执行任务前,扫描线程不停的遍历队列,找到要执行的任务,在遍历时,线程执行的速度时非常快的,这个时候就非常浪费CPU资源。
使用优先级堵塞队列:那么,我们的扫描线程只需要扫描队列的队头,因为 在这个优先级堵塞队列中可以使最先执行的任务放在队头,而且在扫描到这个对头后,我们也可以进入休眠,更一步减少资源浪费。

class MyTimerTask implements Comparable<MyTimerTask>{
    //TimerTask的两个参数
    private Runnable runnable;
    private long time;
    //实例化
    public MyTimerTask(Runnable runnable, long time){
        this.runnable = runnable;
        //计算要执行的时间
        this.time = System.currentTimeMillis() + time;

    }

    public Runnable getRunnable() {
        return runnable;
    }

    public long getTime() {
        return time;
    }
    //比较

    @Override
    public int compareTo(MyTimerTask o) {
        return (int) (time - o.time);
    }
}
class MyTimer{
    //带优先级的堵塞队列
    PriorityQueue<MyTimerTask> queue = new PriorityQueue<>();
    //锁
    Object locker = new Object();
    //实现Timer类中的schedule的方法,接收任务和时间两个参数
    public void schedule(Runnable runnable, long time){
        //多线程环境,对队列操作都加锁,保证线程安全
        synchronized (locker) {
            //任务时间
            MyTimerTask myTimerTask = new MyTimerTask(runnable, time);
            //加入到队列
            queue.offer(myTimerTask);
            //每次添加元素,都唤醒一次循环队列,防止超时
            locker.notify();
        }
    }
    public MyTimer(){
        //在实例化一个MyTimer,那么就就会启动这个扫描线程,进行扫描
        Thread t = new Thread(() -> {
            //使用循环,扫描线程并不是只执行一次
            while (true) {
                try {
                    //加锁,保证线程安全
                    synchronized (locker) {
                        //使用while,不要使用if,防止出现非线程安全
                        while (queue.isEmpty()) {
                            //队列为空,没有要执行的任务,进行等待,堵塞
                            locker.wait();
                        }
                        //取到队列对头,但不出队列,并不一定到时间执行
                        MyTimerTask myTimerTask = queue.peek();
                        //现在的时间
                        long time = System.currentTimeMillis();
                        //现在的时间如果大于任务要执行的时间,队头便出队列
                        if (time >= myTimerTask.getTime()) {
                            queue.poll();
                            //执行任务
                            myTimerTask.getRunnable().run();
                        } else {
                            //如果不到时间,进行等待,计算时间差,防止还没到就被唤醒,带来资源浪费
                            locker.wait(myTimerTask.getTime() - time);
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        //启动!!!
        t.start();
    }
}
public class Test3 {
    public static void main(String[] args) {
        MyTimer myTimer = new MyTimer();
        myTimer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("3秒!");
            }
        },3000);
        myTimer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("2秒");
            }
        },2000);
        myTimer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("1秒");
            }
        },1000);
        System.out.println("开始!");
    }
}

运行结果:
333

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/969082.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

苹果iPhone15系列不再使用皮革保护壳?“FineWoven“官方认证替代

根据9月3日的报道&#xff0c;苹果即将推出的iPhone 15系列将不再使用皮革保护壳&#xff0c;取而代之的将是一种名为"FineWoven"的新材料编织工艺保护壳。 这种保护壳将有十种颜色可供选择&#xff0c;包括黑色、桑葚色、灰褐色、常绿色、太平洋蓝色、紫藤色、古白色…

Elasticsearch安装,Springboot整合Elasticsearch详细教程

Elasticsearch 是一个分布式、RESTful 风格的搜索和数据分析引擎&#xff0c;能够实现近乎实时的搜索。 Elasticsearch官网https://www.elastic.co/cn/ 目录 第一步&#xff1a;下载Elasticsearch 下载7.6.2版本 下载其他版本 第二步&#xff1a;安装Elasticsearch 第三…

【Spring+SpringMVC+Mybatis】SSM框架的整合、思想、工作原理和优缺点的略微讲解

&#x1f680;欢迎来到本文&#x1f680; &#x1f349;个人简介&#xff1a;陈童学哦&#xff0c;目前学习C/C、算法、Python、Java等方向&#xff0c;一个正在慢慢前行的普通人。 &#x1f3c0;系列专栏&#xff1a;陈童学的日记 &#x1f4a1;其他专栏&#xff1a;CSTL&…

Redis布隆过滤器原理

其实布隆过滤器本质上要解决的问题&#xff0c;就是防止很多没有意义的、恶意的请求穿透Redis&#xff08;因为Redis中没有数据&#xff09;直接打入到DB。它是Redis中的一个modules&#xff0c;其实可以理解为一个插件&#xff0c;用来拓展实现额外的功能。 可以简单理解布隆…

2.(Python数模)(优化模型一)线性规划问题

Python解决线性规划问题 参考了以下博文 https://blog.csdn.net/m0_46692607/article/details/126784109?spm1001.2014.3001.5506 目标是解决以下的线性规划&#xff0c;程序计算出目标函数的最大值&#xff0c;并在最大值下取得的x1x2x3对应值。 源代码如下&#xff1a; …

Android studio 实现生成二维码和扫描二维码

效果图 build.gradle(:app)添加依赖 dependencies {implementation com.google.zxing:core:3.3.3implementation com.journeyapps:zxing-android-embedded:3.6.0implementation com.google.zxing:javase:3.0.0 }Manifests.xml <uses-permission android:name"android…

SceneXplain 图片叙事升级:如何让图片听得到

‍SceneXplain 是一个由多模态 AI 驱动的产品服务&#xff0c;它不仅 提供一流的图像和视频标注解决方案&#xff0c;还具备卓越的多模态视觉问答能力&#xff0c;为用户解锁视觉内容的全新维度。 在《图像描述算法排位赛》中&#xff0c;我们探讨了图像描述&#xff08;Image …

DSSM实战中文文本匹配任务

引言 本文我们通过DSSM模型来完成中文文本匹配任务&#xff0c;其中包含了文本匹配任务的一般套路&#xff0c;后续只需要修改实现的模型。 数据准备 数据准备包括 构建词表(Vocabulary)构建数据集(Dataset) 本次用的是LCQMC通用领域问题匹配数据集&#xff0c;它已经分好…

利用 GNU Radio + HackRF 做 FM 收音机

比特的打包与解包 GNU Radio 系列教程&#xff08;四&#xff09;&#xff0d;&#xff0d; 比特的打包与解包_哔哩哔哩_bilibili SDR 教程 —— 利用 GNU Radio HackRF 做 FM 收音机_哔哩哔哩_bilibili

Nginx+keepalived实现高可用项目实战

一、环境搭建 此次项目准备四台虚拟机&#xff1a; 防火墙关闭 安装好nginx&#xff08;一台master,一台back&#xff0c;两台Web服务器&#xff09; ip:(根据自己的进行搭建) 192.168.85.128(master) 192.168.85.129(back) 192.168.85.132(web1) 192.168.85.133(web2)…

排序算法问题

给你一个整数数组 nums&#xff0c;请你将该数组升序排列。 示例 1&#xff1a; 输入&#xff1a;nums [5,2,3,1] 输出&#xff1a;[1,2,3,5] 示例 2&#xff1a; 输入&#xff1a;nums [5,1,1,2,0,0] 输出&#xff1a;[0,0,1,1,2,5] 代码如下&#xff1a; 1.插入排序(简…

Python 中轻松实现串口通信

迷途小书童的 Note 读完需要 3分钟 速读仅需 1 分钟 1 简介 pyserial 是一个 Python 库&#xff0c;它可以让您轻松地与串行端口进行通信。它支持多种操作系统&#xff0c;包括 Windows、Linux 和 macOS。pyserial 模块非常易于使用&#xff0c;并且提供了许多有用的功能。 2 实…

数学建模--二次规划型的求解的Python实现

目录 1.算法流程简介 2.算法核心代码 3.算法效果展示 1.算法流程简介 #二次规划模型 #二次规划我们需要用到函数:Cvxopt.solvers.qp(P,q,G,h,A,b) #首先解决二次规划问题和解决线性规划问题的流程差不多 """ 求解思路如下: 1.针对给定的代求式,转化成标准式…

8.(Python数模)(预测模型一)马尔科夫链预测

Python实现马尔科夫链预测 马尔科夫链原理 马尔科夫链是一种进行预测的方法&#xff0c;常用于系统未来时刻情况只和现在有关&#xff0c;而与过去无关。 用下面这个例子来讲述马尔科夫链。 如何预测下一时刻计算机发生故障的概率&#xff1f; 当前状态只存在0&#xff08;故…

数学建模--最短路径算法的Python实现

目录 1.算法流程简介 2.算法核心代码 3.算法效果展示 1.算法流程简介 #最短路径算法 #针对有向图的最短路径问题,我们有很多的算法能解决. """ 目前主流算法如下所示: Dijkstra算法:Dijkstra算法是一种单源最短路径算法,用于计算从起点到其它所有节点的最短…

VIRTIO-BLK代码分析(0)概述

也无风雨也无晴。- 苏轼&#xff08;宋&#xff09; 接下来介绍VIRTIO相关内容。首先从VIRTIO-BLK开始分析&#xff0c;VIRTIO-BLK各部分交互图如下所示&#xff1a; 这里包含以下几个部分&#xff1a; Guest UserSpace&#xff1a;虚拟机用户空间&#xff0c;如虚拟机中运行f…

Unity中Shader的混合模式Blend

文章目录 前言一、混合的作用就是实现各种半透明效果二、混合操作三、在 Shader 中暴露两个属性 来调节 混合的效果 前言 Unity中Shader的混合模式Blend 一、混合的作用就是实现各种半透明效果 这里用PS里的混合作为例子 没选择混合效果前&#xff0c;显示的效果是这样 选择…

嵌入式开发-IIC通信介绍

IIC&#xff08;Inter-Integrated Circuit&#xff09;是一种两线式串行总线协议&#xff0c;用于连接微控制器及其他外围设备。在IIC总线上的数据传输速率可以是标准模式&#xff08;100Kbit/s&#xff09;&#xff0c;快速模式&#xff08;400Kbit/s&#xff09;和高速模式&a…

决策树算法学习笔记

一、决策树简介 首先决策树是一种有监督的机器学习算法&#xff0c;其采用的方法是自顶向下的递归方法&#xff0c;构建一颗树状结构的树&#xff0c;其具有分类和预测功能。其基本思想是以信息熵为度量构造一棵熵值下降最快的树&#xff0c;到叶子节点处的熵值为零。决策树的构…