简介


  这篇文章我一直在纠结到底要不要写,不想写一来因为定时器用法比较简单,二来是面试中也不常问。后来还是决定写了主要是想把自己分析问题思路分享给大家,让大家在学习过程中能够参考,学习态度我相信大部分人没有问题,特别是正在看我博文的小伙伴那更不用说了!!给你们点个狂力赞。接下来就是学习方法了,我发现近期来咨询我问题的小伙伴学习姿势不对,所以我用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. 深入剖析HashMap

    前言 很高兴遇见你~ HashMap是一个非常重要的集合,日常使用也非常的频繁,同时也是面试重点.本文并不打算讲解基础的使用api,而是深入HashMap的底层,讲解关于HashMap的重点知识.需要 ...

  2. 记一道好VAN的数学题

    2020.4.12 Solution 首先发掘几个性质: \(99\) 个点可以分成 \(33\) 组,每组中个\(3\) 个点组成等边三角形.两两端点相差 \(33\) 条弧. 任意状态下,已经染完 ...

  3. BJOI2015 隐身术

    落谷. Description 给你两个串 \(A.B\).询问 \(B\) 中有多少个非空子串和 \(A\) 的编辑距离不超过 \(K\). Solution 发现 \(K \le 5\),考虑可以 ...

  4. JAVA死锁的检测流程

    步骤一. 查询检测的进程 1.首先查看系统资源占用信息,TOP看一下 发现正在运行的JAVA项目CPU占用率很高,百分之360左右了,那么问题一定出在这个程序中 2 .也可以通过名称查询进程pid 步 ...

  5. STL——容器(List)list 的反序排列

    list.reverse(); //反转链表,比如list包含1, 2, 3, 4, 5五个元素,运行此方法后,list就包含5, 4, 3, 2, 1元素. 1 #include <iostr ...

  6. KafkaMirrorMaker 的不足以及一些改进

    背景 某系统使用 Kafka 存储实时的行情数据,为了保证数据的实时性,需要在多地机房维护多个 Kafka 集群,并将行情数据同步到这些集群上. 一个常用的方案就是官方提供的 KafkaMirrorM ...

  7. Day1 字符编码及编码函数

    ord() 函数 获取字符的整数表示chr() 函数 把整数编码转换为对应字符'\十六进制编码\十六进制编码' 可以将字符的整数编码使用十六进制的方式这样写Python字符串类型为str,在内存中以u ...

  8. IOS实现自动定位和手动选择城市功能

    IOS自动定位使用的是高德地图SDK 在高德开放平台http://lbs.amap.com/api/ios-sdk/down/ 下载2D地图SDK和搜索SDK 将SDK导入工程内 按照高德的配置说明进 ...

  9. 工具-效率工具-listary快速打开文件,win+R使用(99.1.1)

    @ 目录 1.使用WIN+R打开软件 2.使用listary软件 1.使用WIN+R打开软件 添加环境变量 找到需要打开应用的目录 如我的桌面(C:\Users\Public\Desktop) 添加p ...

  10. CSS练习 —— css选择器

    CSS选择器就是 通过选择器来 定位 你要控制的样式的部分,分为以下几种 1.HTML选择符(标签选择器) 就是把HTML标签作为选择符使用 如 p {.......} 网页中所有的P标签采用此样式 ...