java简单实现定时器
wait与sleep
wait:wait的使用必须基于synchronize(对象)块,wait只是将当前线程放入阻塞队列,也就是进入阻塞态,CPU还是可以去跑其他的线程。
sleep:sleep是占着CPU,这段时间之内,CPU什么也不做,就等着时间结束,也就是说,浪费了很多资源(时间)
计时器的分析
计时器的用法,时间一到,就去执行某段代码,每隔固定时间,执行一次代码,要求时间的精度高,在毫秒级别的误差。并且可以控制开始和结束。
计时器核心实现思想
两个线程:其中第一个线程是我们的计时线程,主要负责wait一段固定的时间和唤醒处于同一锁下的另一个线程,而另一个线程在一开始(初始化之后)就要进入阻塞态等待被唤醒,当第一个线程的wait结束之后,立即唤醒第二个线程,让其进入就绪态,这时,如果CPU去运行第一个线程,这个线程会出现短暂的阻塞(时间就是我们设定的时间),在这段时间里就这两个线程而言,CPU只会去运行第二个线程下的其余代码(也就是每隔一段时间就会运行的代码),当运行完毕之后,也就是在第一个线程的wait结束之前,第二个线程再次进入阻塞态,等第一个线程wait的时间一到,立即被唤醒,然后重复上述过程
上代码
// 这是启动线程的代码
public void startClock() {
if (goon) {
return;
}
goon = true;
new DidaWoker();
new Thread(this, "滴答滴答").start();
}
// 这是run方法
@Override
public void run() {
while (goon) {
synchronized(lock) {
try {
lock.wait(delayTime);
lock.notify();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
// 这是第二个线程的类,这里我用一个内部类去实现
class DidaWoker implements Runnable {
public DidaWoker() {
new Thread(this).start();
}
@Override
public void run() {
while (goon) {
synchronized (lock) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 这个方法是一个抽象方法,由外部决定要做什么
doSomething();
}
}
// 测试的代码
public static void main(String[] args) {
Didadida dida = new Didadida() {
// 实现抽象方法
@Override
public void doSomething() {
System.out.println(System.currentTimeMillis());
}
};
dida.setDelayTime(1000);
dida.startClock();
}
这是运行结果,可以看出,时间上的误差,我们可以控制在毫秒级别
限制
这个方法,有一定的限制:我们设定的时间,要比运行doSomething()方法的时间稍长一点,这样才能保证比较精确的计时,一旦doSomething()完全运行一遍的时间过长,可能会导致第一个线程重复wait,相当于等待时间大于我们设定的时间而小于两倍我们设定的时间。
在这个问题的基础上我提出了定时器的另一种实现方式,原文链接如下link