返回顶部
首页 > 资讯 > 精选 >Java多线程如何实现定时器
  • 395
分享到

Java多线程如何实现定时器

2023-07-05 01:07:17 395人浏览 薄情痞子
摘要

这篇文章主要讲解了“Java多线程如何实现定时器”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java多线程如何实现定时器”吧!一. 定时器概述1. 什么是定时器定时器是一种实际开发中非常常

这篇文章主要讲解了“Java多线程如何实现定时器”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java多线程如何实现定时器”吧!

    一. 定时器概述

    1. 什么是定时器

    定时器是一种实际开发中非常常用的组件, 类似于一个 “闹钟”, 达到一个设定的时间之后, 就执行某个指定好的代码.

    比如网络通信中, 如果对方 500ms 内没有返回数据, 则断开连接尝试重连.

    比如一个 Map, 希望里面的某个 key 在 3s 之后过期(自动删除).

    类似于这样的场景就需要用到定时器.

    2. 标准库中的定时器

    标准库中提供了一个 Timer 类, Timer 类的核心方法为schedule.

    Timer类构造时内部会创建线程, 有下面的四个构造方法, 可以指定线程名和是否将定时器内部的线程指定为后台线程(即守护线程), 如果不指定, 定时器对象内部的线程默认为前台线程.

    序号构造方法解释
    1public Timer()无参, 定时器关联的线程为前台线程, 线程名为默认值
    2public Timer(boolean isDaemon)指定定时器中关联的线程类型, true(后台线程), false(前台线程)
    3public Timer(String name)指定定时器关联的线程名, 线程类型为前台线程
    4public Timer(String name, boolean isDaemon) 指定定时器关联的线程名和线程类型

    schedule 方法是给Timer注册一个任务, 这个任务在指定时间后进行执行, TimerTask类就是专门描述定时器任务的一个抽象类, 它实现了Runnable接口.

    public abstract class TimerTask implements Runnable // jdk源码
    序号方法解释
    1public void schedule(TimerTask task, long delay)指定任务, 延迟多久执行该任务
    2public void schedule(TimerTask task, Date time)指定任务, 指定任务的执行时间
    3public void schedule(TimerTask task, long delay, long period)连续执行指定任务, 延迟时间, 连续执行任务的时间间隔, 毫秒为单位
    4public void schedule(TimerTask task, Date firstTime, long period)连续执行指定任务, 第一次任务的执行时间, 连续执行任务的时间间隔
    5public void scheduleAtFixedRate(TimerTask task, Date firstTime, long period)与方法4作用相同
    6public void scheduleAtFixedRate(TimerTask task, long delay, long period)与方法3作用相同
    7public void cancel()清空任务队列中的全部任务, 正在执行的任务不受影响

    代码示例:

    import java.util.Timer;import java.util.TimerTask;public class TestProgram {    public static void main(String[] args) {        Timer timer = new Timer();        timer.schedule(new TimerTask() {            @Override            public void run() {                System.out.println("执行延后3s的任务!");            }        }, 3000);        timer.schedule(new TimerTask() {            @Override            public void run() {                System.out.println("执行延后2s后的任务!");            }        }, 2000);                timer.schedule(new TimerTask() {            @Override            public void run() {                System.out.println("执行延后1s的任务!");            }        }, 1000);    }}

    执行结果:

    Java多线程如何实现定时器

    观察执行结果, 任务执行结束后程序并没有结束, 即进程并没有结束, 这是因为上面的代码定时器内部是开启了一个线程去执行任务的, 虽然任务执行完成了, 但是该线程并没有销毁; 这和自己定义一个线程执行完成 run 方法后就自动销毁是不一样的, Timer 本质上是相当于线程池, 它缓存了一个工作线程, 一旦任务执行完成, 该工作线程就处于空闲状态, 等待下一轮任务.

    二. 定时器的简单实现

    首先, 我们需要定义一个类, 用来描述一个定时器当中的任务, 类要成员要有一个Runnable, 再加上一个任务执行的时间戳, 具体还包含如下内容:

    • 构造方法, 用来指定任务和任务的延迟执行时间.

    • 两个get方法, 分别用来给外部对象获取该对象的任务和执行时间.

    • 实现Comparable接口, 指定比较方式, 用于判断定时器任务的执行顺序, 每次需要执行时间最早的任务.

    class MyTask implements Comparable<MyTask>{    //要执行的任务    private Runnable runnable;    //任务的执行时间    private long time;    public MyTask(Runnable runnable, long time) {        this.runnable = runnable;        this.time = time;    }    //获取当前任务的执行时间    public long getTime() {        return this.time;    }    //执行任务    public void run() {        runnable.run();    }    @Override    public int compareTo(MyTask o) {        return (int) (this.time - o.time);    }}

    然后就需要实现定时器类了, 我们需要使用一个数据结构来组织定时器中的任务, 需要每次都能将时间最早的任务找到并执行, 这个情况我们可以考虑用优先级队列(即小根堆)来实现, 当然我们还需要考虑线程安全的问题, 所以我们选用优先级阻塞队列 PriorityBlockingQueue 是最合适的, 特别要注意在自定义的任务类当中要实现比较方式, 或者实现一下比较器也行.

    private PriorityBlockingQueue<MyTask> queue = new PriorityBlockingQueue<>();

    我们自己实现的定时器类中要有一个注册任务的方法, 用来将任务插入到优先级阻塞队列中;

    还需要有一个线程用来执行任务, 这个线程是从优先级阻塞队列中取出队首任务去执行, 如果这个任务还没有到执行时间, 那么线程就需要把这个任务再放会队列当中, 然后线程就进入等待状态, 线程等待可以使用sleep和wait, 但这里有一个情况需要考虑, 当有新任务插入到队列中时, 我们需要唤醒线程重新去优先级阻塞队列拿队首任务, 毕竟新注册的任务的执行时间可能是要比前一阵拿到的队首任务时间是要早的, 所以这里使用wait进行进行阻塞更合适, 那么唤醒操作就需要使用notify来实现了.

    实现代码如下:

    //自己实现的定时器类class MyTimer {    //扫描线程    private Thread t = null;    //阻塞队列,存放任务    private PriorityBlockingQueue<MyTask> queue = new PriorityBlockingQueue<>();    public MyTimer() {        //构造扫描线程        t = new Thread(() -> {           while (true) {               //取出队首元素,检查队首元素执行任务的时间               //时间没到,再把任务放回去               //时间到了,就执行任务               try {                   synchronized (this) {                       MyTask task = queue.take();                       long curTime = System.currentTimeMillis();                       if (curTime < task.getTime()) {                           //时间没到,放回去                           queue.put(task);                           //放回任务后,不应该立即就再次取出该任务                           //所以wait设置一个阻塞等待,以便新任务到时间或者新任务来时后再取出来                           this.wait(task.getTime() - curTime);                       } else {                           //时间到了,执行任务                           task.run();                       }                   }               } catch (InterruptedException e) {                   throw new RuntimeException(e);               }           }        });        t.start();    }        public void schedule (Runnable runnable, long after) {        //获取当前时间的时间戳再加上任务时间        MyTask task = new MyTask(runnable, System.currentTimeMillis() + after);        queue.put(task);        //每次当新任务加载到阻塞队列时,需要中途唤醒线程,因为新进来的任务可能是最早需要执行的        synchronized (this) {            this.notify();        }    }}

    要注意上面扫描线程中的synchronized并不能只要针对wait方法加, 如果只针对wait加锁的话, 考虑一个极端的情况, 假设的扫描线程刚执行完put方法, 这个线程就被cpu调度走了, 此时另有一个线程在队列中插入了新任务, 然后notify唤醒了线程, 而刚刚并没有执行wait阻塞, notify就没有起到什么作用, 当cpu再调度到这个线程, 这样的话如果新插入的任务要比原来队首的任务时间更早, 那么这个新任务就被错过了执行时间, 这些线程安全问题真是防不胜防啊, 所以我们需要保证这些操作的原子性, 也就是上面的代码, 扩大锁的范围, 保证每次notify都是有效的.

    那么最后基于上面的代码, 我们来测试一下这个定时器:

    public class TestDemo23 {    public static void main(String[] args) {        MyTimer timer = new MyTimer();        timer.schedule(new Runnable() {            @Override            public void run() {                System.out.println("2s后执行的任务1");            }        }, 2000);        timer.schedule(new Runnable() {            @Override            public void run() {                System.out.println("2s后执行的任务1");            }        }, 1000);    }}

    执行结果:

    Java多线程如何实现定时器

    感谢各位的阅读,以上就是“Java多线程如何实现定时器”的内容了,经过本文的学习后,相信大家对Java多线程如何实现定时器这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

    --结束END--

    本文标题: Java多线程如何实现定时器

    本文链接: https://lsjlt.com/news/348839.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    猜你喜欢
    • Java多线程如何实现定时器
      这篇文章主要讲解了“Java多线程如何实现定时器”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java多线程如何实现定时器”吧!一. 定时器概述1. 什么是定时器定时器是一种实际开发中非常常...
      99+
      2023-07-05
    • Java多线程之定时器Timer的实现
      目录标准库中的Timer模拟实现Timer标准库中的Timer 标准库中有一个Timer类,java.util.Timer,核心方法为schedule,schedule有两个参数,第...
      99+
      2022-11-13
      Java 多线程 定时器Timer Java 定时器Timer Java 定时器
    • java多线程如何实现
      java实现多线程的方法:(推荐:java视频教程)方式一:继承Thread类的方式创建一个继承于Thread类的子类重写Thread类中的run():将此线程要执行的操作声明在run()创建Thread的子类的对象调用此对象的start(...
      99+
      2022-02-13
      java
    • java如何实现多线程
      Java多线程是Java高级特性之一,通过多线程,我们可以实现多任务同时协同工作,在一定情况下提升程序效率,但是Java多线程仍要慎重使用。 (推荐学习:java课程)首先第一点,Java多线程需要较高的编码技巧,一...
      99+
      2019-06-27
      java教程 java
    • Java多线程案例之定时器
      文章目录 一. 定时器概述1. 什么是定时器2. 标准库中的定时器 二. 定时器的简单实现 一. 定时器概述 1. 什么是定时器 定时器是一种实际开发中非常常用的组件, 类似于一个 “...
      99+
      2023-09-10
      java 定时器 Timer 多线程 线程安全
    • Java如何实现多线程、线程同步
      这篇文章主要介绍了Java如何实现多线程、线程同步的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Java如何实现多线程、线程同步文章都会有所收获,下面我们一起来看看吧。1 多线程1.1 进程进程:是正在运行的程...
      99+
      2023-06-30
    • java如何实现多线程Thread
      这篇文章将为大家详细讲解有关java如何实现多线程Thread,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。start()我们先来看看API中对于该方法的介绍:使该线程开始执行;Java 虚拟机调用该线程...
      99+
      2023-05-30
      java thread
    • linux多线程定时器如何使用
      在Linux上使用多线程定时器,可以使用以下步骤:1. 包含必要的头文件:```c#include #include #includ...
      99+
      2023-10-09
      linux
    • 如何使用Qt实现线程与定时器
      这篇文章主要介绍如何使用Qt实现线程与定时器,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、定时器QTimer类The QTimer class provides repetitive and single-sho...
      99+
      2023-06-26
    • java多线程中如何实现线程并发库
      本篇文章给大家分享的是有关java多线程中如何实现线程并发库,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。多线程之线程并发库原子性操作类java.util.concurrent...
      99+
      2023-06-19
    • Java中的多线程如何实现线程通信
      这篇文章将为大家详细讲解有关Java中的多线程如何实现线程通信,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。Java多线程中线程间的通信一、使用while方式来实现线程之间的通信packag...
      99+
      2023-05-31
      java 多线程 线程通信
    • Java多线程案例之定时器详解
      目录一.什么是定时器二.标准库中的定时器(timer)2.1什么是定时器2.2定时器的使用三.实现定时器3.1什么是定时器3.2最终实现代码一.什么是定时器 定时器也是软件开发中的一...
      99+
      2022-11-13
      Java多线程 定时器 Java 定时器 Java 多线程
    • Java如何实现UDP多线程在线咨询
      这篇文章主要介绍Java如何实现UDP多线程在线咨询,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!Java是什么Java是一门面向对象编程语言,可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式系统应用程序。具...
      99+
      2023-06-14
    • SpringBoot定时任务多线程实现示例
      测试Spring Boot定时任务冲突时,使用的线程数量 引入依赖: Spring Boot 2.6.1 <dependency> <group...
      99+
      2024-04-02
    • 什么是Java多线程,如何实现
      目录什么是进程?什么是线程?什么是线程安全?添加一个状态呢?如何确保线程安全?synchronizedlock总结什么是进程? 电脑中时会有很多单独运行的程序,每个程序有一个独立的进...
      99+
      2024-04-02
    • Java线程之Timer定时器
      定时/计划功能主要使用的就是Timer对象,它在内部还是使用多线程的方式进行处理,所以它和线程技术还是有非常大的关联。Timer类主要作用就是设置计划任务,但封装任务的类却是TimerTask类。TimerTask类是一个抽象类。执行任务的...
      99+
      2018-03-22
      java教程 Java 线程 Timer 定时器
    • Spring多线程通过@Scheduled实现定时任务
      目录一、前言二、定时任务调度注解@Scheduled三、使用@Async实现异步调度建立spring线程池为异步调度方法指定线程池一、前言 技术的入门大多比较简单,把别人的代码复制过...
      99+
      2024-04-02
    • Java如何实现多线程循环打印
      这篇文章将为大家详细讲解有关Java如何实现多线程循环打印,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。wait-notify循环打印问题可以通过设置目标值,每个线程想打印目标值,如果拿到锁后这次轮到的数...
      99+
      2023-06-22
    • java多线程Synchronized如何实现可见性
      这篇文章主要为大家展示了“java多线程Synchronized如何实现可见性”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“java多线程Synchronized如何实现可见性”这篇文章吧。Sy...
      99+
      2023-06-21
    • Java中线程池自定义如何实现
      这篇“Java中线程池自定义如何实现”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Java中线程池自定义如何实现”文章吧。线...
      99+
      2023-07-05
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作