详解 定时器 的基本实现
在本人之前的博文中所讲解过定时器的问题
有很多同学可能会很好奇它是如何实现的
那么,在本篇博文中,本人将简单来实现下定时器:
基本思路:
首先呢,我们来思考这样的问题 :
我们该如何实现代码段延迟执行呢?
对于 右转哥的铁粉 以及 JavaSE功底比较棒的同学来说,
这个问题很简单 —— 线程等待
那么,根据以上思想,
本人来给出一个通过线程等待的方式实现的延迟执行 的 定时器:
实现代码:
package edu.youzg.timer_impl.core;
public abstract class DidaDida implements Runnable{
public static final long DEAFLT_DELAY = 1000; // 默认延迟时间
private long delay; // 延迟时间
private volatile boolean goon; // 用于 开启/关闭线程
private Object lock; // 避免线程安全问题 的锁
public DidaDida() {
this(DEAFLT_DELAY);
}
public DidaDida(long delay) {
this.lock = new Object();
this.delay = delay;
}
public void setDelay(long delay) {
this.delay = delay;
}
public abstract void doing();
public void start() {
if (this.goon == true) {
return;
}
this.goon = true;
new Thread(this).start();
}
public void stop() {
if (this.goon==false) {
return;
}
this.goon = false;
}
@Override
public void run() {
while (goon) {
synchronized (lock) {
try {
lock.wait(delay);
new InnerWorker();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private class InnerWorker implements Runnable{
public InnerWorker() {
new Thread(this).start();
}
@Override
public void run() {
doing();
}
}
}
优化思路:
优化方案:
在上面的代码中,主要应用了Object的对象充当锁
但是,在本人《详解 锁》一文中,讲到了:
JDK1.5之后,Java提供了一个专门针对同步互斥的接口 —— Lock接口 和它的实现类们
在此处,我们只需要运用到:
lock.lock();
需要同步的代码块;
lock.unlock();
来实现同步
运用
condition.await(long time,TimeUnit unit)
来代替
object.wait(long timeout)
扩展:
原生方法 | 封装优化方法 |
---|---|
Object类 中的 wait()方法 |
Condition类 中的 await()方法 |
Object类 中的 wait(long timeout)方法 |
Condition类 中的 await(long time,TimeUnit unit)方法 |
Object类 中的 notify()方法 |
Condition类 中的 singal()方法 |
Object类 中的 notifyAll()方法 |
Condition类 中的 singalAll()方法 |
Thread类 中的 静态方法 sleep() (格式:Thread.sleep(休眠时长大小)) |
TimeUnit类 中的 静态方法 sleep() (格式:TimeUnit.单位枚举.sleep(休眠时长大小)) |
那么,本人就运用Lock接口的api来优化下上文中的代码:
优化版本:
package edu.youzg.timer_impl.core;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @Author: Youzg
* @CreateTime: 2020-07-17 09:23
* @Description: 带你深究Java的本质!
*/
public abstract class Didadida implements Runnable {
private static final long DEFAULT_DELAY_TIME = 1000; // 默认延迟时间
private volatile boolean goon; // 用于 开启/关闭线程
private long delay; // 延迟时间
private Lock lock; // 安全“锁”对象
private Condition condition; // 用于控制 当前线程 的 状态
public Didadida() {
this(DEFAULT_DELAY_TIME);
}
public Didadida(long delay) {
this.delay = delay;
this.lock = new ReentrantLock();
this.condition = lock.newCondition();
}
public void setDelay(long delay) {
this.delay = delay;
}
public void start() {
if (this.goon) {
return;
}
this.goon = true;
new Thread(this).start();
}
public void stop() {
if (!this.goon) {
return;
}
this.goon = false;
}
protected abstract void doTask();
@Override
public void run() {
while (this.goon) {
lock.lock();
try {
// await() 方法释放对象锁
// 参1 ———— 大小
// 参2 ———— 单位(此处设置的单位是 毫秒)
this.condition.await(this.delay, TimeUnit.MILLISECONDS); // 1. 被唤醒 2. 超过设定的时间 3. 阻塞状态
new InnerWorker();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
private class InnerWorker implements Runnable {
public InnerWorker() {
new Thread(this).start();
}
@Override
public void run() {
doTask();
}
}
}
使用展示:
那么,现在本人来给出一个使用该定时器来完成指定指令的类:
(本人要求每隔0.5秒输出一下这条语句,并且总共运行2s)
package edu.youzg.timer_impl.test;
public class DemoDidadida {
private Didadida dida;
private static int times = 0;
public DemoDidadida() {
dida = new Didadida(2000) {
@Override
public void doTask() {
int time = ++times;
System.out.println("第" + time + "次开始:" + System.currentTimeMillis());
}
};
}
public void runup() {
dida.start();
try {
Thread.sleep(10000); //这里我们设置总共运行10s
} catch (InterruptedException e) {
}
dida.stop();
}
}
现在,本人来给出一个测试类:
package edu.youzg.timer_impl.test;
public class Test {
public static void main(String[] args){
new DemoDidaDida().runup();
}
}
那么,现在本人来展示下运行结果:
可以看到,结果的确按照我们的要求 —— 每隔2s(2000ms)输出一次
但是又存在 些微误差,这是因为我们开启线程 等语句也是会耗时的
但是,大体上来看,这些误差还是能够被忽略的
以上就是 定时器 的 基本实现步骤了!
那么,在本人之后的博文中,也会对这里的工具代码有所应用,
希望同学们能够领悟到本篇博文的思想
最后,想要了解JDK版本源码实现的同学,可以观看如下博文:
JDK源码剖析:
请观看博文 —— 《【源码剖析】定时器 详解》