定时器:
- 1.在约定好的时间点上,执行某个任务
- 2.每间隔一定时间就执行某个任务
在JAVA中实现定时器功能要用的2个类是Timer,TimerTask
Timer类是用来履行任务的类,它接受1个TimerTask做参数
Timer有两种执行任务的模式,最经常使用的是schedule,它可以以以下几种方式执行任务:
1:在某个时间(Data),
2:在某个固定的时间以后(long delay).
3.间隔一定时间就执行某个任务(long period )
import java.util.concurrent.*;
/**
* 定时器:
* 1.在约定好的时间点上,执行某个任务
* 2.每间隔一定时间就执行某个任务
*/
public class MyTimer {
private BlockingQueue<Runnable> queue = new PriorityBlockingQueue();
public MyTimer(int count) {
for (int i = 0; i < count; i++) {
new Thread(new MyWorker(queue)).start();
}
}
/**
* 定时任务
* @param task 需要执行的任务
* @param delay 从当前时间延迟多少毫秒执行任务
* @param period 间隔时间; <=0就忽略掉,>0需要每间隔给定时间,就执行任务
*/
public void schedule(Runnable task,long delay,long period){
try {
queue.put(new MyTimerTask(task,System.currentTimeMillis()+delay,period));
synchronized (queue){
queue.notifyAll();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static class MyWorker implements Runnable{
private BlockingQueue<Runnable> queue;
public MyWorker(BlockingQueue<Runnable> queue){
this.queue = queue;
}
@Override
public void run() {
try {
while (true) {
//blockingQueue本身就是线程安全的,所以这里的方法调用不用放在同步代码块中
MyTimerTask task = (MyTimerTask) queue.take();
synchronized (queue) {
long current = System.currentTimeMillis();
if (task.next < current) {
queue.wait(task.next-current );
queue.put(task);
} else {
task.task.run();
if (task.period > 0) {
task.next = task.next + task.period;
queue.put(task);
}
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private static class MyTimerTask implements Runnable,Comparable<MyTimerTask>{
//定时任务
private Runnable task;
//下次执行时间
private long next;
private long period;
public MyTimerTask(Runnable task,long next,long period){
this.task = task;
this.next = next;
this.period = period;
}
@Override
public void run() {
}
@Override
public int compareTo(MyTimerTask o) {
return 0;
}
}
public static void main(String[] args) {
new MyTimer(4).schedule(new Runnable() {
@Override
public void run() {
System.out.println("起床了");
}
},3000,1000);
}
}
这里主要用了一个MyTimer来表示一个定时器,使用BlockingQueue阻塞队列来存储任务和执行时间(delay),间隔执行时间(period),并使用内部类MyTimerTask将他们传给阻塞队列queue,同时使用内部类MyWorker来执行任务
首先main方法启动4个线程,然后MyTimer调用 MyWorker并传入了一个阻塞式队列并启动,
然后定时器就会从阻塞队列中取出任务,即queue.take();但是如果当前时间大于下次执行时间,说明定时器仍需等待,直到下次执行时间到来,同时要将该任务放回阻塞队列并阻塞等待.
而如果时间已到,则执行任务,若间隔执行任务的时间(period)>0,则下次任务执行时间需要延长period,同样这里应该使用synchronized关键字加锁