简介


  这篇文章我一直在纠结到底要不要写,不想写一来因为定时器用法比较简单,二来是面试中也不常问。后来还是决定写了主要是想把自己分析问题思路分享给大家,让大家在学习过程中能够参考,学习态度我相信大部分人没有问题,特别是正在看我博文的小伙伴那更不用说了!!给你们点个狂力赞。接下来就是学习方法了,我发现近期来咨询我问题的小伙伴学习姿势不对,所以我用Java中定时器Timer为案例整理下我的学习方法。万丈高楼平地起,所以我一贯的做法都是先用最简单,最简单,最简单案例先行!那就先来个Hello World吧!

案例1:定时器打印Hello World!


import java.text.ParseException;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask; /**
* @author :jiaolian
* @date :Created in 2021-01-05 20:42
* @description:Timer启动后内置线程不销毁
* @modified By:
* 公众号:叫练
*/
public class TimerThreadNoStopTest { //TimerTask为抽象类,继承TimerTask类必须要实现里面抽象方法
private static class Task extends TimerTask {
@Override
public void run() {
System.out.println("hello world!");
}
} public static void main(String[] args) throws ParseException { Timer timer = new Timer();
Task task = new Task();
long currenTime = System.currentTimeMillis();
//提交Task线程;程序按传入日期运行
timer.schedule(task,new Date(currenTime));
}
}

  如上面程序代码,Timer提交了一个task任务并传入了currenTime当前时间,控制台马上打印了"hello world!",如果schedule传入的第二个参数是new Date(currenTime+2000)表示延迟2m执行task任务,这里简单使用方法就不过多的描述了,但是大家在学习过程中遇到疑惑的问题一定要多尝试多写代码测试,这是理解代码必不可少的一部分,不要以为能看懂就不写了,像我在学习过程中,如果稍微有疑问,我会立马动手写代码测试,因为我知道有时候自己可能懂了,但那可能不是真正的懂,只有代码能检验出来!下图是程序控制台打印结果。如果大家执行了你会发现一个问题,程序一直不结束运行,也就是程序不死。那是什么导致这样的结果呢?

线程不死问题?


  原因分析:如下图所示,主线程执行Timer timer = new Timer();会创建了一个新的子线程timer,timer线程通过死循环来取队列里面的任务task[1],队列其实就是一个数组实现TaskQueue,队列里面如果没有任务,那timer线程就会一直等待直到主线程调用schedule提交任务,主线程就会将task加入到TaskQueue队列数组并通知timer线程执行任务并删除队列的第一个任务,如果是主线程提交的是定时任务,就会将任务重新加入队列,任务执行完毕后,如果此时队列为空,timer线程就会继续等待任务提交到队列,一直会循环上面的过程。如果想退出timer线程,可以调用cancel方法会退出死循环。线程不死原因是timer线程一直在等待主线程提交任务,timer线程和主线程通信是通过调用wait/notify实现。我们之前做生产者/消费者案例时详细介绍过,这里老铁不再重复叙述了,可以去翻看文章《母鸡下蛋实例》。这个过程中,我们发现timer是一个单线程,我是单线程怎么了?单线程也有错吗?思考个问题,如果timer这个单线程提交了两个任务怎么办?我们看下面代码!

案例2:单线程问题


import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask; /**
* @author :jiaolian
* @date :Created in 2021-01-06 10:53
* @description:多任务执行测试,任务只能顺序执行;
* @modified By:
* 公众号:叫练
*/
public class MultTaskExecuteTest { private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); private static class MyTask1 extends TimerTask { @Override
public void run() {
System.out.println("task1 begin:"+SIMPLE_DATE_FORMAT.format(new Date()));
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("task1 end:"+SIMPLE_DATE_FORMAT.format(new Date()));
}
} private static class MyTask2 extends TimerTask { @Override
public void run() {
System.out.println("task2 begin:"+SIMPLE_DATE_FORMAT.format(new Date()));
System.out.println("task2 end:"+SIMPLE_DATE_FORMAT.format(new Date()));
}
} public static void main(String[] args){
Timer timer = new Timer();
MyTask1 myTask1 = new MyTask1();
MyTask2 myTask2 = new MyTask2();
long curTime = System.currentTimeMillis();
System.out.println("当前时间:"+SIMPLE_DATE_FORMAT.format(curTime));
timer.schedule(myTask1,new Date(curTime));
//myTask1执行时间过长,myTask2 被执行时间会被延迟;
timer.schedule(myTask2,new Date(curTime+1000));
} }

  如上面程序代码,timer线程提交了两个任务myTask1,myTask2,myTask1任务会立刻执行,myTask2计划延迟一秒执行,myTask1执行过程中会休息10秒钟,我们观察任务执行时间如下图所示,myTask2任务是等待myTask1任务执行完毕后再执行的,其实myTask2只是延迟一秒执行,结果却延迟了10秒,说明了timer单线程会串行化任务导致myTask2延迟执行,所以Timer是适合轻量级定时任务,如果设置大量任务,可能会存在延迟执行情况

定时器实际应用场景


  在日常系统开发中,相信你遇到过类似需要重复执行的任务,比如每天凌晨2点清理数据库某张表的垃圾数据,页面显示设备(服务器)运行状态也需要每隔3秒调用设备状态接口查询设备情况等,这些功能开发都需要用到定时器,当然Timer定时器也有自身的缺陷,比如它是单线程的,后面会说到线程池中的定时器是多线程的,可以优化Timer,所以掌握Timer定时器为后面学习高阶内容打好基础。知其然知其所以然,在实际应用中我们能得心应手!

学习方法心得


  大家可以看到我最近几篇文章分析多线程花了不少精力都在谈论可见性,原子性,母鸡下蛋生成消费问题等问题,因为这些特性是理解多线程的基础,在我看来基础又特别重要,所以怎么反复写我认为都不过分,在这之前有很多新手或者有2到3年工作经验的童鞋经常会问我关于Java的学习方法,还有一大批童鞋一上来就要做springboot,ssm项目,我是不建议这么干的,你在做项目之前先要了解下servlet,mvc思想啊,这是基础。我给他们的建议就是要扎实基础,别上来就学高级的知识点或者框架,比如ReentrantLock源码,线程池框架,就像你玩游戏,一开始你就玩难度级别比较高的,一旦坡度比较高你就会比较难受吃力更别说对着书本了,这就是真正的从入门到放弃的过程。同时在学习的时候别光思考,觉得这个知识点自己会了就过了,这是不够的需要多写代码,多实践,你在这个过程中再去加深自己对知识的理解与记忆,其实有很多知识你看起来是理解了,但是你没有动手去实践,也没有真正理解,这样只看不做的方法我是不推荐的,本人本科毕业后工作7年,一直从事Java一线的研发工作,担任Java高级研发工程师,中间也带过团队,因为自己曾经踏着坑过来的,对学习程序还是有一定的心得体会,我会在今后的日子里持续整理把一些经验和知识方面的经历分享给大家,希望大家喜欢关注我。我是叫练,叫个口号就开始练!

总结下来就是两句话:多动手,扎实基础,从简单做起,然后慢慢深入!

 

 

总结


  我们用代码简述timer定时器提交任务,并说明了timer是单线程的适合轻量级的定时任务,这是它的缺陷。鉴于篇幅有限其中timer还有很多方法我们没有用代码贴出来,比如定时执行,延迟执行,timer取消方法,希望大家一一对着书本执行起来,给大家推荐本多线程入门学习书籍,《Java多线程编程核心技术》,书本以案例为主,也没有特别难理解的案例,非常适合新手学习。如果需要pfd版请联系我!喜欢的请点赞加关注哦。我是叫练【公众号】,边叫边练。

Java中定时器Timer致命缺点(附学习方法)的更多相关文章

  1. Java进阶(十八)Java实现定时器(Timer)

    Java实现定时器(Timer) 绪 在应用开发中,经常需要一些周期性的操作,比如每5分钟执行某一操作等.对于这样的操作最方便.高效的实现方式就是使用java.util.Timer工具类.java.u ...

  2. java多线程--定时器Timer的使用

    定时的功能我们在手机上见得比较多,比如定时清理垃圾,闹钟,等等.定时功能在java中主要使用的就是Timer对象,他在内部使用的就是多线程的技术. Time类主要负责完成定时计划任务的功能,就是在指定 ...

  3. java中定时器总结

    java实现定时器的四种方式: 一. /** * 延迟20000毫秒执行 java.util.Timer.schedule(TimerTask task, long delay) */ public ...

  4. 2.1多线程(java学习笔记) java中多线程的实现(附静态代理模式)

    一.多线程 首先我们要清楚程序.进程.线程的关系. 首先进程从属于程序,线程从属于进程. 程序指计算机执行操作或任务的指令集合,是一个静态的概念. 但我们实际运行程序时,并发程序因为相互制约,具有“执 ...

  5. Java中定时器相关实现的介绍与对比之:Timer和TimerTask

    Timer和TimerTask JDK自带,具体的定时任务由TimerTask指定,定时任务的执行调度由Timer设定.Timer和TimerTask均在包java.util里实现. 本文基于java ...

  6. java中定时器的简单使用

    1.首先肯定是容器一启动就要启动定时器,所以我们可以选择把定时器写在一个监听器里,容器一启动所以监听器也就跟着启动,然后定时器就可以工作了. 第一步,把自己写的监听器加到web.xml中: 第二步,写 ...

  7. Java中使用Timer和TimerTask实现多线程

    转自:http://www.bdqn.cn/news/201305/9303.shtml 摘要:Timer是一种线程设施,用于安排以后在后台线程中执行的任务.可安排任务执行一次,或者定期重复执行,可以 ...

  8. Java中的Timer和TimerTask在Android中的用法(转)

    转自:http://blog.csdn.net/zuolongsnail/article/details/8168689 在开发中我们有时会有这样的需求,即在固定的每隔一段时间执行某一个任务.比如UI ...

  9. [ImportNew]Java中的Timer类和TimerTask类

    http://www.importnew.com/9978.html java.util.Timer是一个实用工具类,该类用来调度一个线程,使它可以在将来某一时刻执行. Java的Timer类可以调度 ...

随机推荐

  1. Leetcode学习笔记(1)

    scrapy爬虫的学习告一段落,又因为现在在学习数据结构,做题平台是lettcode:https://leetcode-cn.com/ 每周都要交一次做题的笔记,所以把相关代码和思路同时放在博客上记录 ...

  2. 廖雪峰官网学习js 字符串

    操作字符串: length()           长度 totoLowerCase() 小写 toUpperCase()      大写 trim()            移除空白 charAt( ...

  3. 在Chrome、Firefox等高版本浏览器中实现低延迟播放海康、大华RTSP

    一.背景 现在到处是摄像头的时代,随着带宽的不断提速和智能手机的普及催生出火热的网络直播行业,新冠病毒的大流行又使网络视频会议系统成为商务会议的必然选择,因此RTSP实时视频流播放及处理不再局限于安防 ...

  4. 配置OSPF与BFD联动

    组网图形 OSPF与BFD联动简介 双向转发检测BFD(Bidirectional Forwarding Detection)是一种用于检测转发引擎之间通信故障的检测机制.BFD对两个系统间的.同一路 ...

  5. css进阶 02-CSS布局

    02-CSS布局 #前言 #常见的布局属性 (1)display 确定元素的显示类型: block:块级元素. inline:行内元素. inline-block:对外的表现是行内元素(不会独占一行) ...

  6. vue第十六单元(element-ui vue-lazyload 等常用插件)

    第十六单元(element-ui vue-lazyload 等常用插件) #课程目标 1.掌握插件的引入方式 2.精通UI框架 3.掌握前端常见的几种效果实现 #知识点 一.elementUI的使用 ...

  7. PHP MySQL 快速导入10万条数据

    项目背景 数据来源:所有数据均为外部导入,最大数据量在10w+ 输出数据:导出经过业务处理之后的数据 使用框架:fastadmin 涉及的问题: 1.数据读取 2.数据保存 使用数据:10w+ 解决方 ...

  8. Vue 修改成功之后我做了什么

    Vue 修改成功之后我做了什么 背景:前端将修改的数据传递到后端,后端返回成功之后,我们要将数据及时显示出来. 霸道方法一:重新请求接口 柔和方法二:修改成功之后的数据传递到源数据中,进行双向绑定显示 ...

  9. vue实现点击样式高亮

    •在data中定义即将渲染的数据,及active data() {     return {       active:'',//选中样式     };   }, 1 2 3 4 5 6 7 8 9 ...

  10. 扫描条形码获取商品信息(iOS 开发)

    一.导入ZBarSDK及其依赖库(这不是本文侧重点)     1.下载地址 https://github.com/bmorton/ZBarSDK     2.导入头文件 #import "Z ...