计时器的实现

在平时的开发中,我们常常遇到一些这样的需求,比如一天打一个报表,一周打一个报表,一月打一个报表,每天把数据库里几年没登录的用户删除掉等等,我们往往会利用计时器来完成这些业务,所谓的计时器就是能够根据准确时间来完成业务的调用。
首先计时器应该是一个线程,它独立于业务,且尽量开销小,因为它存活的时间是可能非常久的。
其次业务函数调用的时间不算在计时器计时的时间内,因此调用业务函数应该也是一个线程。
频繁的切换上下文,或者创建消亡线程会非常影响时间的准确性,所以我们采用等待/通知模板完成。
一个系统中可能需要多个计时器,需要考虑到锁的应用。
那么我们的总体思想如下,单独计时的线程我们叫didadida,计时时间到了要去调用方法的线程我们叫didaworker;

package com.hzy.dadidida;

public abstract class DidaDida implements Runnable{
	private volatile Boolean goon = false;
	private int DefaultTime = 1000;
	private int waitTime = 0;
	private volatile Object lock; 
	public void startDida() {
		//启动线程开始计时调用,在系统中每一个计时器线程都有一个单独的锁,互不影响。
		lock = new Object();
		goon = true;
		DoSomethingWorker dsw = new DoSomethingWorker();
		new Thread(dsw,"didaworkerThread").start();
		new Thread(this,"didaThread").start();
	}
	public void setWaitTime(int time) {
		this.waitTime = time;
	}
	/**
 * 计时器启动之前
 */
public abstract void onDidaBegin();
/**
 * 计时器完成之后
 */
public abstract void onDidaAfter();
/**
 * 计时时间到而产生的动作
 */
public abstract void itTimeToDoSomething();
	@Override
	public void run() {
		if(waitTime==0) {
			waitTime = DefaultTime;
		}
		onDidaBegin();
		while(goon) {
			synchronized (lock) {
				try {
					lock.wait(waitTime);
					//此处应该唤醒的线程来完成时间到的动作
					lock.notifyAll();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			
		}
		onDidaAfter();
	}
	public void stopDida() {
		goon = false;
	}
	
	public class DoSomethingWorker implements Runnable{

		public void run() {
			while(goon) {
			synchronized (lock) {
				try {
					//等待计时器线程的唤醒
					lock.wait();
					if(goon) {
						itTimeToDoSomething();
						}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			}
		}
		
	}
}

上面这个就是使用了等待通知模板,自始至终我们都只有两个线程,减少了线程创建和销毁的开销。

package com.hzy.dadidida;
//自己写的一个工具,只是输出时前面加上时间
import com.mec.util.CurrentTime;

public class DidaMutex extends DidaDida{
	private String name;
	private int count;
    public void start(String name) {
    	this.name = name;
    	count = 0;
    	startDida();
    }	
    public void stop() {
    	stopDida();
    }
	@Override
	public void onDidaBegin() {
	 //CurrentTime.ogMessage是自己写的一个工具,只是输出时前面加上时间
		System.out.println(CurrentTime.logMessage("dida开始工作"));
	}

	@Override
	public void onDidaAfter() {
		System.out.println(CurrentTime.logMessage("dida线程结束"));
	}

	@Override
	public void itTimeToDoSomething() {
		count++;
		System.out.println(CurrentTime.logMessage("dida线程"+name+"在第"+count+"次工作"));
	}

}

提供给使用者让其自己写自己需要调用的方法。
做个测试:

public class Test {
	public static void main(String[] args) {
		DidaMutex dm1 = new DidaMutex();
		dm1.start("1");
		DidaMutex dm2 = new DidaMutex();
		dm2.start("2");
	}
}

在这里插入图片描述
每调用几次会有毫秒级别的误差,而且两个线程之间互不影响。
为啥会有毫秒级别的误差呢,原因是我们的线程唤醒也是要耗费时间的啊,我们打输出语句也是耗费时间的,但毫秒级别的误差我们还是能够接受的,如何能够让线程把时间卡的非常准确小编还没有接触到。感谢您的阅读,再会。
指导老师:微易码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值