JAVAEE-定时器案例

这篇具有很好参考价值的文章主要介绍了JAVAEE-定时器案例。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

设置一个时间,当时间到了的时候,定时器就会去自动执行某个逻辑.

timer简介

1.创建计时器

Timer timer=new Timer();//创建计时器

2.创建任务

timer.schedule(new TimerTask(){//接口,这里不能使用lambada表达式,lambada表达式要求接口只有一个函数,这里有多个
public void run(){
System.out.println("hello 1000");
}

},1000);//第二个參数是推迟时间,delay,计时器创建好之后,什么时候进行执行

3.关掉计时器

timer.cancel();//停掉计时器,未执行的任务停止

这里timer里面的任务执行完了也并不会结束,因为他并不知道是否还会添加新的任务进去,

处在严阵以待的状态

此时如果我们想要结束,应该使用cancel主动去结束.

完整代码:

package thread;

import java.lang.annotation.Target;
import java.util.Timer;
import java.util.TimerTask;

public class ThreadDemo27 {
    public static void main(String[] args) throws InterruptedException {
        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 2000");
            }
        },2000);

     timer.schedule(new TimerTask() {
        @Override
        public void run() {
            System.out.println("hello 1000");
        }
    },1000);
        System.out.println("hello main");
        Thread.sleep(5000);
        timer.cancel();
}
    }



JAVAEE-定时器案例,java,开发语言

Timer里面的内容

1)需要有一个线程,负责掐时间,等任务到达合适的时间,这个线程就负责执行

还需要有一个队列/数组,能够保存所有schedule进来的任务

直观的想,就是这个线程需要不断的去扫描上述队列中的每个任务是否到时间了,到时间了就需要去执行.

在这里每个任务都是带有delay时间的,肯定是先执行时间小的,后执行时间大的,我们可以使用优先级队列,只需要关注队首元素是否到时间,如果到时间了,就需要进行执行,

在此处,我们使用PriortyQueue(线程不安全,需要我们主动加锁控制),

PriorityBlockingQueue(线程安全)在此处场景中,不太好控制,容易出问题

自定义计时器:

1.首先我们先定义一个类,用来存放时间和任务.

class MYTIMETASK{
    private Runnable runnable;//此处为执行的任务代码
    private long time;//此处为执行任务的时间,此处的时间是一个相对时间,此处的时间是一个ms级别的时间戳
    //构造方法
    //获取时间的方法
    public long getTime(){
        return  this.time;
    }
    //提供任务执行的接口
    public void run(){
        this.runnable.run();
    }
    public MYTIMETASK(Runnable runnable,long delay){
        this.runnable=runnable;
        this.time=System.currentTimeMillis()+delay;
    }
}

但是我们在定义计时器MYTIME这个类的时候,需要用一个优先级队列来进行存储task任务,因此task必须是可以进行比较的,不然会报错,因此,task这个类就要实现Comparable这个接口

这是改进后的MTTIMETASK类


/**
 * 用来存放执行的时间和任务
 */
class MYTIMETASK implements  Comparable<MYTIMETASK>{
    private Runnable runnable;//此处为执行的任务代码
    private long time;//此处为执行任务的时间,此处的时间是一个相对时间,此处的时间是一个ms级别的时间戳
    //构造方法
    //获取时间的方法
    public long getTime(){
        return  this.time;
    }
    //提供任务执行的接口
    public void run(){
        this.runnable.run();
    }
    public MYTIMETASK(Runnable runnable,long delay){
        this.runnable=runnable;
        this.time=System.currentTimeMillis()+delay;
    }

    @Override
    public int compareTo(MYTIMETASK o) {
        return (int)(this.time-o.time);//这里是long类型,要进行强制类型转换
    }
}

这是MYTIMER类的实现

class MYTIMER{
    private Thread t=null;//定义一个线程来不断地进行扫描,看是否有任务到时间了,不断地去扫描
    private PriorityQueue<MYTIMETASK>queue=new PriorityQueue<>();//此处定义一个优先级队列来存放任务,
    //但是这里需要注意,我们的优先级队列在进行存储自定义数据时,需要实现Comparable接口方法.,因此上述代码应做出改动
    public void schedule(Runnable runnable,long delay){//使用schedule进行任务的添加
        MYTIMETASK task=new MYTIMETASK(runnable,delay);
        queue.offer(task);//进行任务的添加
    }
    //在构造方法里面创建一个线程来进行扫描,严阵以待
    public MYTIMER(){
        t=new Thread(()->{
            while(true){
                if(queue.isEmpty())
                {
                    continue;//如果队列为空,则不能进行peek,要循环到有任务进来了,才可以执行当前逻辑
                }
                //如果不为空,我们则需要查看队列顶部的任务是否到了执行的时间
                MYTIMETASK task=queue.peek();
                if(System.currentTimeMillis()>=task.getTime()){
                    task.run();//到了执行任务的时间,则需要进行执行
                    queue.poll();//执行了则需要进行出队列操作
                }

            }
        });
        t.start();//开启这个线程
    }

}

但是这里面仍然有不足的地方..

首先这是一个多线程,我们就要查看是否设计线程安全问题.

当构造方法的t线程和主线程在调用schedule方法时,两个线程会同时对queue这个队列进行操作.

JAVAEE-定时器案例,java,开发语言

如上图而言,这样就会出现线程不安全,因此我们要给他们进行加锁.

加上锁了之后,线程是安全了,但是还有一个问题.

JAVAEE-定时器案例,java,开发语言 

当队列一开始为空的时候,有图中的线程会一直执行while循环,每次都会快速的解锁,但是他每次都会先一步左边的线程拿到锁,因为左边的锁是处于沉睡的状态,才被唤醒会竞争不过右边的线程,那么就会造成一直都是右边的线程拿到锁,但是又无法继续执行下去.这种情况,我们就应该使用wait方法,让右边的线程主动进入WAITING阻塞状态,主动放弃锁的竞争,给左边的线程一点时间,等到左边的线程放进了任务的时候,再去通知右边线程去执行.

JAVAEE-定时器案例,java,开发语言相同的道理,如果此时右侧队列的第一个任务的时间过于长的话,他就会一直争夺锁,因此我们也要给他设置一个带时间的wait方法,不然左边的线程在他一直循环争夺锁的过程是拿不到锁的.

最终完整代码:


/**
 * 用来存放执行的时间和任务
 */
class MYTIMETASK implements  Comparable<MYTIMETASK>{
    private Runnable runnable;//此处为执行的任务代码
    private long time;//此处为执行任务的时间,此处的时间是一个相对时间,此处的时间是一个ms级别的时间戳
    //构造方法
    //获取时间的方法
    public long getTime(){
        return  this.time;
    }
    //提供任务执行的接口
    public void run(){
        this.runnable.run();
    }
    public MYTIMETASK(Runnable runnable,long delay){
        this.runnable=runnable;
        this.time=System.currentTimeMillis()+delay;
    }

    @Override
    public int compareTo(MYTIMETASK o) {
        return (int)(this.time-o.time);//这里是long类型,要进行强制类型转换
    }
}

/**
 * 计时器,用来判断当前哪一个任务该执行了
 */
class MYTIMER{
    private Thread t=null;//定义一个线程来不断地进行扫描,看是否有任务到时间了,不断地去扫描
    private PriorityQueue<MYTIMETASK>queue=new PriorityQueue<>();//此处定义一个优先级队列来存放任务,
    //但是这里需要注意,我们的优先级队列在进行存储自定义数据时,需要实现Comparable接口方法.,因此上述代码应做出改动
    private Object locker1=new Object();
    public void schedule(Runnable runnable,long delay){//使用schedule进行任务的添加
        synchronized (locker1) {
            MYTIMETASK task = new MYTIMETASK(runnable, delay);
            queue.offer(task);//进行任务的添加
            locker1.notify();
        }
    }
    
    //提供一个cancel方法来进行计时器任务的结束
    public void cancel(){
        t.interrupt();
    }
    //在构造方法里面创建一个线程来进行扫描,严阵以待
    public MYTIMER(){
        t=new Thread(()->{
            while(!Thread.currentThread().isInterrupted()){
                try {
                    synchronized (locker1) {
                        while (queue.isEmpty()) {
                            locker1.wait();
                            //continue;//如果队列为空,则不能进行peek,要循环到有任务进来了,才可以执行当前逻辑
                        }
                        //如果不为空,我们则需要查看队列顶部的任务是否到了执行的时间
                        MYTIMETASK task = queue.peek();
                        if (System.currentTimeMillis() >= task.getTime()) {
                            task.run();//到了执行任务的时间,则需要进行执行
                            queue.poll();//执行了则需要进行出队列操作
                        }
                        else{
                            locker1.wait(task.getTime()-System.currentTimeMillis());
                //此处的wait有两种方式,一种是当没有任务添加进来的时候,这个线程会一直等到//时间到了继续再去执行,
//另外一种是又有新添加的任务,这个线程要扫描当前任务时间最近的线程,这个新添加的任务就有可能是最近时间最接近的任务

                        }
                    }
                }
                catch (InterruptedException e){
                        break;
                }

            }
        });
        t.start();//开启这个线程
    }

}

测试代码:

public class Main{

    public static void main(String[] args) throws InterruptedException {
  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);
        Thread.sleep(5000);
        timer.cancel();
    }
}

运行结果: 

JAVAEE-定时器案例,java,开发语言

以上就是计时器的自我实现,感谢各位大佬的三连.文章来源地址https://www.toymoban.com/news/detail-755427.html

到了这里,关于JAVAEE-定时器案例的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【javaEE】阻塞队列、定时器、线程池

    目录 🌴一、阻塞队列 1.概念 2.生产者消费者模型 3.阻塞队列的实现 🏹二、定时器 1.引出定时器 2.定时器的实现 🔥三、线程池 1.引出线程池 2.ThreadPoolExecutor 构造方法 3.标准数据库的4种拒绝策略【经典面试题】【重点掌握】 4.线程池的实现   1.概念 ✨对于队列,首先我们想

    2023年04月21日
    浏览(32)
  • 【JavaEE初阶】 定时器详解与实现

    定时器也是软件开发中的一个重要组件. 类似于一个 “闹钟”. 达到一个设定的时间之后, 就执行某个指定好的代码 定时器是一种实际开发中非常常用的组件. 比如网络通信中, 如果对方 500ms 内没有返回数据, 则断开连接尝试重连. 比如一个 Map, 希望里面的某个 key 在 3s 之后过

    2024年02月06日
    浏览(24)
  • 【JavaEE初阶】多线程(四)阻塞队列 定时器 线程池

    概念 阻塞队列是一种特殊的队列. 也遵守 “ 先进先出 ” 的原则. 阻塞队列能是一种线程安全的数据结构, 并且具有以下特性: 当队列满的时候, 继续入队列就会阻塞, 直到有其他线程从队列中取走元素. 当队列空的时候, 继续出队列也会阻塞,直到有其他线程往队列中插入元素

    2023年04月26日
    浏览(41)
  • 多线程案例(3)-定时器

    大家好,我是晓星航。今天为大家带来的是 多线程案例三 相关的讲解!😀 定时器是什么 定时器也是软件开发中的一个重要组件. 类似于一个 “闹钟”. 达到一个设定的时间之后, 就执行某个指定 好的代码. 定时器是一种实际开发中非常常用的组件. 比如网络通信中, 如果对方

    2024年02月14日
    浏览(28)
  • STM32自学☞定时器外部时钟案例

    本案例主要是通过外部时钟实现对射式红外传感器的计次,在oled显示屏上显示CNT的次数 #include \\\"stm32f10x.h\\\" #include \\\"stm32f10x_tim.h\\\" #include \\\"timer_interrupt.h\\\" #include \\\"stdint.h\\\" //初始化函数 void Timer_Init(void) {  /*开启时钟*/  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //开启TIM2的时钟  RCC_A

    2024年02月22日
    浏览(33)
  • 【Linux】Linux定时器使用及代码案例

    在 Linux 中,可以使用定时器来实现一些定时任务,例如定时发送信号、定时执行某个函数等。定时器的初始化通常包括以下几个步骤: 定义定时器结构体:首先需要定义一个定时器结构体,用于存储定时器的相关信息。在 Linux 中,可以使用 timer_t 类型来表示定时器结构体。

    2024年02月04日
    浏览(30)
  • 多线程案例 | 单例模式、阻塞队列、定时器、线程池

    单例模式 单例模式是 设计模式 的一种 什么是设计模式? 设计模式好比象棋中的 “棋谱”,红方当头炮,黑方马来跳,针对红方的一些走法,黑方应招的时候有一些固定的套路,按照套路来走局势就不会吃亏,也就发明了一组\\\"棋谱\\\",称为设计模式 软件开发中也有很多常见

    2024年02月15日
    浏览(40)
  • C语言实现定时器

    代码解释: #include stdio.h #include windows.h 这两行是引入所需的标准库头文件。 void CALLBACK timer_handler(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) {     printf(\\\"Timer expired!n\\\"); } 定义了一个回调函数 timer_handler,当定时器到期时会被调用。在此示例中,它只简单地打印一条消息表示定时

    2024年02月12日
    浏览(28)
  • 学习笔记|定时器|STC中断|定时器时间计算|STC32G单片机视频开发教程(冲哥)|第十一集:定时器的作用和意义

    什么是定时器:定时器-与非网 上节课的一段代码: TimeCount++然后一个延时1毫秒,每运行1ms,变量就会加一。 系统已经运行了多少个毫秒。 实际使用时的代码如下, 判断按键有沿有按下的时候,我们等待按键松开,还有一个while循环。 如果没有松开,会一直死在这一行。所以,

    2024年02月09日
    浏览(45)
  • Java定时器

    目录 什么是定时器? 如何使用定时器? schedule Timer的构造方法 cancel 定时器的模拟实现 思路分析 实现过程 完整代码 定时器: 即在设定的时间时执行某事的设备(例如闹钟,在指定的时间响铃),Java中的定时器会在到达设定的时间后,执行指定的代码 Java标准库中提供了一

    2024年02月03日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包