首页 > 编程语言 >【JavaEE】【多线程】定时器

【JavaEE】【多线程】定时器

时间:2024-10-30 15:15:57浏览次数:3  
标签:执行 定时器 MyTimerTask schedule JavaEE task 线程 多线程 public

目录


一、定时器简介

定时器:就相当于一个闹钟,当我们定的时间到了,那么就执行一些逻辑。

1.1 Timer类

Java的标准库中提供了在java.util包下的Timer类作为定时器。
有如下的构造方法:
四种:

  1. timer() 无参构造;
  2. timer(boolean isDaemon) 创建的线程都是后台线程;
  3. timer(String name) 给定时器中创建的线程名字;
  4. timer(String name, boolean isDaemon) 创建的线程都是后台线程,也给定时器中创建的线程名字。

在Timer类中的核心方法是schedule方法。

  1. schedule(Timer task, Date time) 到达time时刻后执行task任务;
  2. schedule(Timer task, Date firstTime, long period) 到达time时刻后重复执行task任务,每次相隔period时间;
  3. schedule(Timer task, long delay) 在delay时间后执行task任务;
  4. schedule(Timer task, long delay, long period) 在delay时间后重复执行task任务,每次相隔period时间;
  5. scheduleAtFixedRate(Timer task, Date firstTime, long period) 到达time时刻后重复执行task任务,每次执行period时间;
  6. scheduleAtFixedRate(Timer task, long delay, long period) 在delay时间后重复执行task任务,每次执行period时间;

schedule的第一个参数是TimerTask类,这是一个实现了Runnable接口的抽象类。

1.2 使用案例

我们使用schedule方法来打印不同时间执行不同内容。

import java.util.Timer;
import java.util.TimerTask;

public class Demo {
    public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("3000ms后执行");
            }
        },3000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("1000ms后执行");
            }
        },1000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("2000ms后执行");
            }
        },2000);
    }
}

结果如下:会按照等待时间由小到大打印内容,并且执行完之后并不会结束,这是因为这些线程是前台线程。

二、实现简易定时器

自己实现的定时器主要要考虑下面几个内容:

  1. 设计一个类表示任务,对应TimerTask类;
  2. 使用优先级队列来组织多个任务,每次根节点都是等待时间最短的任务;
  3. 实现schedule方法,把任务添加到队列中;
  4. 额外创建一个线程,负责执行队列中的任务,根据时间来执行(即判断是否到了该执行的时间了)。

2.1 MyTimerTask类

这个类中需要:

  • 将要执行的任务,和任务要执行的时刻记录下来,
  • 并且这个任务还要有通过时刻比较得方法(即实现Comparator接口,重写CompareTo方法),便于后面存储进优先级队列。

代码:

class MyTimerTask implements Comparable<MyTimerTask>{
    //记录任务
    private Runnable task = null;
    //记录执行任务的时刻
    private long current = 0;

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

    public Runnable getTask() {
        return task;
    }

    public long getCurrent() {
        return current;
    }

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

2.2 实现schedule方法

我们实现schedule方法:

  • 只需要将当前的任务传入队列中即可。
  • 将参数Runnable的任务和时刻用来创建MyTimerTask类,在入队即可。
  • 我们还要使用notify为后面的线程中因为队列为空调用wait进入阻塞状态提供唤醒。

代码:

private PriorityQueue<MyTimerTask> queue = new PriorityQueue<>();

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

2.3 构造方法

在构造方法中额外创建一个线程,负责执行队列中的任务,根据时间来执行(即判断是否到了该执行的时间了)。

  • 我们在最外层使用一层死循环来不断去读取队列中的任务。
  • 如果队列空了,那么我们就出这次循环,但是如果使用continue的话,还是会在循环的去判断直到队列不为空为止。这样的消耗很高,我们可以使用wait等待schedule方法入队列后;来唤醒这个线程。
  • 如果没有到达执行时间,我们也要出这次循环,但是使用continue也会导致在从现在这个时刻到执行时刻之间一直进行无意义的执行上面的代码,消耗很高,我们这里直接使用带参数的wait方法等待还需要的时间即可。
  • 到达执行时间直接执行任务并出队列即可。
  • 最后不要忘记启动这个线程。

代码:

public MyTimer() {
        Thread thread = new Thread(()-> {
            try {
                while(true) {  //循环拿任务,直到任务队列为空
                    synchronized (this) {
                        while (queue.isEmpty()) {  //任务队列为空
                            this.wait();
                        }
                        MyTimerTask task = queue.peek();
                        
                        if(task.getCurrent() > System.currentTimeMillis()) { //没到执行时间 
                            this.wait(task.getCurrent() - System.currentTimeMillis());
                        } else {
                            task.run();
                            queue.poll();
                        }
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        thread.start();
    }

2.4 总代码

总代码如下:

class MyTimerTask implements Comparable<MyTimerTask>{
    //记录任务
    private Runnable task = null;
    //记录执行任务的时刻
    private long current = 0;

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

    public Runnable getTask() {
        return task;
    }

    public long getCurrent() {
        return current;
    }

    @Override
    public int compareTo(MyTimerTask o) {
        return (int)(this.current - o.current);
    }
    public void run() {
        task.run();
    }


}

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

    public void schedule(Runnable task, long delay) {
        synchronized (this) {
            MyTimerTask myTimerTask = new MyTimerTask(task, System.currentTimeMillis() + delay);
            queue.offer(myTimerTask);
            this.notify();
        }
    }
    public MyTimer() {
        Thread thread = new Thread(()-> {
            try {
                while(true) {  //循环拿任务,直到任务队列为空
                    synchronized (this) {
                        while (queue.isEmpty()) {  //任务队列为空
                            this.wait();
                        }
                        MyTimerTask task = queue.peek();

                        if(task.getCurrent() > System.currentTimeMillis()) { //没到执行时间
                            this.wait(task.getCurrent() - System.currentTimeMillis());
                        } else {
                            task.run();
                            queue.poll();
                        }
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        thread.start();
    }
}

2.5 测试

如果在main中执行下面这样的代码,也使用schedule方法来打印不同时间执行不同内容,会与上面使用案例的结果一样。

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

结果如下:会按照等待时间由小到大打印内容,并且执行完之后并不会结束,这是因为这些线程是前台线程。

标签:执行,定时器,MyTimerTask,schedule,JavaEE,task,线程,多线程,public
From: https://blog.csdn.net/yj20040627/article/details/143163957

相关文章

  • 多线程编程ExecutorService用法
    以下内容均来自ChatGPT提供的示例,用于自学ExecutorService是Java中用于管理和控制线程池的接口,通常用来简化多线程编程。它提供了一组方法,允许我们在异步任务执行完毕后关闭线程池、调度任务等操作。以下是几个常见的使用场景和示例代码:1.使用ExecutorService执行简单任务......
  • 操作系统(7) (POSIX--Linux线程编程---使用多线程计算平方pthread_t/create/join应用)
    1.代码目的我们希望创建一个程序:启动多个线程,每个线程计算一个数字的平方值。每个线程将计算结果返回给主线程。主线程接收每个线程的返回值,并将结果打印出来。在这个例子中,我们通过传递不同的参数给每个线程,来让每个线程计算不同数字的平方值。2.代码实现以下是代码的......
  • [python]多线程快速入门
    前言线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。由于CPython的GIL限制,多线程实际为单线程,大多只用来处理IO密集型任务。Python一般用标准库threading来进行多线程编程。基本使用方式1,创建threading.Thread类的示例importthreadi......
  • zynq7000使用私有定时器中断
    Zynq-7000系列SoC(SystemonChip)的定时器系统是由几个不同的定时器模块组成的,这些定时器可以满足广泛的嵌入式应用需求。主要包括:全局定时器(GlobalTimer)特点:全局定时器是一个64位的计时器,存在于Cortex-A9处理器内核中,提供一个全局的时间基准。用途:主要用于需要......
  • Springboot+vue的公司日常考勤管理系统(有报告),Javaee项目,springboot vue前后端分离项目
    演示视频:Springboot+vue的公司日常考勤管理系统(有报告),Javaee项目,springbootvue前后端分离项目。项目介绍:本文设计了一个基于Springboot+vue的前后端分离的公司日常考勤管理系统,采用M(model)V(view)C(controller)三层体系结构,通过Spring+SpringBoot+Mybatis+Vue+Maven......
  • ssm+vue的班级事务管理系统(有报告)。Javaee项目,ssm vue前后端分离项目。
    演示视频:ssm+vue的班级事务管理系统(有报告)。Javaee项目,ssmvue前后端分离项目。项目介绍:采用M(model)V(view)C(controller)三层体系结构,通过Spring+SpringMvc+Mybatis+Vue+Maven来实现。MySQL数据库作为系统数据储存平台,实现了基于B/S结构的Web系统。界面简洁,操作简单......
  • ssm+vue的超市会员管理系统(有报告)。Javaee项目,ssm vue前后端分离项目。
    演示视频:ssm+vue的超市会员管理系统(有报告)。Javaee项目,ssmvue前后端分离项目。项目介绍:采用M(model)V(view)C(controller)三层体系结构,通过Spring+SpringMvc+Mybatis+Vue+Maven来实现。MySQL数据库作为系统数据储存平台,实现了基于B/S结构的Web系统。界面简洁,操作简单......
  • 多线程应用在鸿蒙 HarmonyOS Next 中的内存管理与 GC 实战
    本文旨在深入探讨华为鸿蒙HarmonyOSNext系统(截止目前API12)的技术细节,基于实际开发实践进行总结。主要作为技术分享与交流载体,难免错漏,欢迎各位同仁提出宝贵意见和问题,以便共同进步。本文为原创内容,任何形式的转载必须注明出处及原作者。在构建高性能应用时,尤其是需要处理大......
  • JavaSE——多线程2:线程池详解
    一、线程池介绍        线程池(ThreadPool)是一种基于多线程处理的服务器架构,它预先创建并维护一组线程,用于处理异步任务或并发请求。线程池的设计目的是减少创建和销毁线程的开销,提高系统的响应速度和吞吐量。(一)线程池的主要核心原理创建一个池子,池子中是空的。......
  • 【记录一下】lazarus多线程的用法
    网友“蓝天白云”在qq群问lazarus多线程的问题,以下代码是“啊D”给出的,但编译出错。procedureTForm1.Button2Click(Sender:TObject);beginmemo1.Text:='start...';TThread.CreateAnonymousThread(procedurevari:integer;beginSleep(1000);for......