传统线程技术中有个定时器,定时器的类是Timer,我们使用定时器的目的就是给它安排任务,让它在指定的时间完成任务。所以先来看一下Timer类中的方法(主要看常用的TimerTask()方法):

前面两个是在指定延迟后执行或者重复执行,后面两个是在指定时间执行或者重复执行。我们以前两个为例来研究一下定时器的使用。

先写一个简单的使用定时器的demo,然后慢慢引申。

public class TraditionalTimer {

	public static void main(String[] args) {
//简单定时器的demo
new Timer().schedule(new TimerTask() {
@Override
public void run() {
//实际中会扔一个对象进来,我们就可以在这里操作这个对象的所有方法了
System.out.println("--boom--");//爆炸
}
}, 2000,3000); //打印秒钟,一秒输出一次,用来方便观察的
while(true) {
System.out.println(new Date().getSeconds());
try {
Thread.sleep(1000);
} catch(Exception e) {
e.printStackTrace();
}
}
}
}

我们用匿名内部类来定义了一个TimerTask对象,需要重写run()方法,然后运行这个程序,可以看出来第一次2秒钟后打印“--boom--,后面每隔3秒打印一次。

我们也可以自己来实现上面这个重复执行,我们用定时器的“连环套”!也就是定时器中再套定时器,一个定时器任务执行完了,在任务的最后再装一个定时器。那么我们需要先定义一个自己的定时器任务,在自己的定时器任务中再装一个定时器,把自定义的定时器任务扔进去。然后我们开启定时器的时候把自己定义的定时器任务扔进去即可。如下:

public class TraditionalTimer {

	public static void main(String[] args) {

		//自定义一个定时器任务
class MyTimerTask extends TimerTask {
@Override
public void run() {
System.out.println("--boom--");
//任务执行完再装一个定时器,扔进自定义的定时器任务
new Timer().schedule(new MyTimerTask(), 3000);
}
}
new Timer().schedule(new MyTimerTask(), 2000);//外面开启定时器 while(true) {//打印秒钟,一秒输出一次
System.out.println(new Date().getSeconds());
try {
Thread.sleep(1000);
} catch(Exception e) {
e.printStackTrace();
}
}
}
}

这样的话,我们通过定时器的“连环套”很轻松的实现了连环爆炸。但是现在问题来了,上面提供的方法中重复执行都是每隔固定的时间,如果我想要隔2秒执行一次,再隔4秒执行一次,再隔2秒执行一次,再隔4秒执行一次……这该如何实现呢?

可以这样,我们定义一个全局的私有成员变量来记录爆炸次数,奇数的时候隔2秒炸,偶数的次数的话隔4秒炸,或者反过来也行,修改如下:

public class TraditionalTimer {

	private static int count = 0; //记录爆炸的次数
public static void main(String[] args) { class MyTimerTask extends TimerTask {
@Override
public void run() {
count = (count + 1) % 2; //结果只有0和1
System.out.println("--boom--");
new Timer().schedule(new MyTimerTask(), 2000+2000*count);//根据count结果设定新的定时时间
}
}
new Timer().schedule(new MyTimerTask(), 2000); while(true) {//打印秒钟,一秒输出一次
System.out.println(new Date().getSeconds());
try {
Thread.sleep(1000);
} catch(Exception e) {
e.printStackTrace();
}
}
}
}

这样的话,我们就实现了自定义爆炸间隔了。上面这个是通过定义一个全局私有变量来实现,其实我们也可以这么干:不是要实现两个不同时间间隔的连环炸么?我可以定义两个定时器任务A和B,在A执行完开启定时器,把B任务装进去,B执行完开启定时器把A装进去,这样也可以。如下:

public class TraditionalTimer {

	public static void main(String[] args) {

		new Timer().schedule(new MyTimerTaskA(), 2000);//A和B随便开一个

		while(true) {//打印秒钟,一秒输出一次
System.out.println(new Date().getSeconds());
try {
Thread.sleep(1000);
} catch(Exception e) {
e.printStackTrace();
}
}
} }
//自定义两个定时器任务类,继承TimerTask即可
class MyTimerTaskA extends TimerTask { @Override
public void run() {
System.out.println("--boomA--");
new Timer().schedule(new MyTimerTaskB(), 4000);
}
}
class MyTimerTaskB extends TimerTask { @Override
public void run() {
System.out.println("--boomB--");
new Timer().schedule(new MyTimerTaskA(), 2000);
}
}

这样就可以实现自定义时间间隔的连环炸了。传统的定时器技术就总结这么多吧~

更多优质文章和资源,请关注公众号:【程序员私房菜】。

Java并发基础02. 传统线程技术中的定时器技术的更多相关文章

  1. Java并发基础01. 传统线程技术中创建线程的两种方式

    传统的线程技术中有两种创建线程的方式:一是继承Thread类,并重写run()方法:二是实现Runnable接口,覆盖接口中的run()方法,并把Runnable接口的实现扔给Thread.这两种方式 ...

  2. Java并发基础03. 传统线程互斥技术—synchronized

    在多个线程同时操作相同资源的时候,就会遇到并发的问题,如银行转账啊.售票系统啊等.为了避免这些问题的出现,我们可以使用synchronized关键字来解决,下面针对synchronized常见的用法做 ...

  3. Java并发基础05. 传统线程同步通信技术

    先看一个问题: 有两个线程,子线程先执行10次,然后主线程执行5次,然后再切换到子线程执行10,再主线程执行5次--如此往返执行50次. 看完这个问题,很明显要用到线程间的通信了, 先分析一下思路:首 ...

  4. Java并发编程(02):线程核心机制,基础概念扩展

    本文源码:GitHub·点这里 || GitEE·点这里 一.线程基本机制 1.概念描述 并发编程的特点是:可以将程序划分为多个分离且独立运行的任务,通过线程来驱动这些独立的任务执行,从而提升整体的效 ...

  5. Java并发:搞定线程池(中)

    向线程池提交任务 1.1 execute()     用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功.输入的是一个Runnable实例. public void execute(Ru ...

  6. java并发基础(五)--- 线程池的使用

    第8章介绍的是线程池的使用,直接进入正题. 一.线程饥饿死锁和饱和策略 1.线程饥饿死锁 在线程池中,如果任务依赖其他任务,那么可能产生死锁.举个极端的例子,在单线程的Executor中,如果一个任务 ...

  7. Java 并发基础

    Java 并发基础 标签 : Java基础 线程简述 线程是进程的执行部分,用来完成一定的任务; 线程拥有自己的堆栈,程序计数器和自己的局部变量,但不拥有系统资源, 他与其他线程共享父进程的共享资源及 ...

  8. 【搞定 Java 并发面试】面试最常问的 Java 并发基础常见面试题总结!

    本文为 SnailClimb 的原创,目前已经收录自我开源的 JavaGuide 中(61.5 k Star![Java学习+面试指南] 一份涵盖大部分Java程序员所需要掌握的核心知识.欢迎 Sta ...

  9. java并发基础(二)

    <java并发编程实战>终于读完4-7章了,感触很深,但是有些东西还没有吃透,先把已经理解的整理一下.java并发基础(一)是对前3章的总结.这里总结一下第4.5章的东西. 一.java监 ...

随机推荐

  1. css 居中方法

    垂直居中 利用“精灵元素”(ghost element)技术实现垂直居中,即在父容器内放一个100%高度的伪元素,让文本和伪元素垂直对齐,从而达到垂直居中的目的. .ghost-center { po ...

  2. git add的各种情况分类

    ·  git add -A  提交所有变化 ·  git add -u  提交被修改(modified)和被删除(deleted)文件,不包括新文件(new) ·  git add .  提交新文件( ...

  3. Node.Js的热更新服务——supervisor

    因为目前项目每次修改文件要看效果,必须重启服务:node app.js再进入浏览器看效果,很是麻烦.所幸的是有很多第三方的管理工具(supervisor,hotnode,forever,pm2等),当 ...

  4. Linux监控系统相关资源和运行状态命令整理

    #前言:Linux系统自带了些实时查看监控系统运行状态的相关命令,接下来我们就来了解一下. #首先我们先来了解一下什么是进程 #进程:是Linux用来表示正在运行的程序的一种抽象概念,Linux系统上 ...

  5. 【WPF学习】第五十九章 理解控件模板

    最近工作比较忙,未能及时更新内容,敬请了解!!! 对于可视化树的分析引出了几个有趣问题.例如,控件如何从逻辑树表示扩张成可视化树表示? 每个控件都有一个内置的方法,用于确定如何渲染控件(作为一组更基础 ...

  6. 树链剖分与倍增求LCA

    树链剖分与倍增求\(LCA\) 首先我要吐槽机房的辣基供电情况,我之前写了一上午,马上就要完成的时候突然停电,然后\(GG\)成了送链剖分 其次,我没歧视\(tarjan LCA\) 1.倍增求\(L ...

  7. ssh 公钥 下载选择的时候 下拉选择 ssh 然后 git clone

    ssh 公钥 下载选择的时候 下拉选择 ssh 然后 git clone

  8. iviewadmin url 加入 Router base #viewDesignAdmin

    router/index.js const router = new Router({   routes,   base: '/viewDesignAdmin/',   mode: 'history' ...

  9. webpack学习(一):webpack的安装和命令行

    本教程可以学习到如下内容: 1.webpack的安装 2.利用webpack命令打包js文件 3.如何在js文件里面引用css并将css文件在页面里面生效 4.学习webpack相关的高级的一些参数, ...

  10. 【Weiss】【第03章】练习3.20:中缀表达式转后缀表达式

    [练习3.20] a.编写一个程序将中缀表达式转换为后缀表达式,该中缀表达式含括号及四则运算. b.把幂操作符添加到你的指令系统中去. c.编写一个程序将后缀表达式转化为中缀表达式. Answer: ...