java 内置定时器实现定时任务和自定义定时任务

首先,如果要执行一些简单的定时器任务,无须做复杂的控制,也无须保存状态,那么可以考虑使用JDK 入门级的定期器Timer来执行重复任务。

JDK中,定时器任务的执行需要两个基本的类:
    java.util.Timer;
    java.util.TimerTask;

要运行一个定时任务,最基本的步骤如下:
1、建立一个要执行的任务TimerTask,TimerTask是一个抽象类,由 Timer 安排为一次执行或重复执行的任务。它有一个抽象方法run()----计时器任务要执行的操作。因此,每个具体的任务类都必须继承TimerTask类,并且重写run()方法。
2、创建一个Timer实例,通过Timer提供的schedule()方法,将 TimerTask加入到定时器Timer中,同时设置执行的规则即可。
 
当程序执行了Timer初始化代码后,Timer定时任务就会按照设置去执行。
 
Timer中的schedule()方法是有多种重载格式的,以适应不同的情况。该方法的格式如下:
 void schedule(TimerTask task, Date time)
          安排在指定的时间执行指定的任务。
 void schedule(TimerTask task, Date firstTime, long period)
          安排指定的任务在指定的时间开始进行重复的固定延迟执行。
 void schedule(TimerTask task, long delay)
          安排在指定延迟后执行指定的任务。
 void schedule(TimerTask task, long delay, long period)
          安排指定的任务从指定的延迟后开始进行重复的固定延迟执行。

import java.util.Scanner;
import java.util.Timer;
import java.util.TimerTask;

public class TimerTest {

	public static void main(String[] args) {

		Timer timer = new Timer();
		timer.schedule(new MyTask(), 1000, 2000);// 在1秒后执行此任务,每次间隔2秒,如果传递一个Data参数,就可以在某个固定的时间执行这个任务.

		Scanner sc = new Scanner(System.in);
		System.out.println("输入任何字符串停止任务:" + sc.next());
		timer.cancel();
	}

	/**
	 * 定时任务实体
	 * @author Administrator
	 *
	 */
	static class MyTask extends TimerTask {
		@Override
		public void run() {
			System.out.println("run");
		}
	}

}

下面给出一个复杂点的例子,其中告诉大家怎么退出单个TimerTask,怎么退出所有Task

import java.util.Scanner;
import java.util.Timer;
import java.util.TimerTask;

public class TimerTest1 {
	public static void main(String[] args) {
		Timer timer = new Timer();
		MyTask myTask1 = new MyTask();
		myTask1.setInfo("task-1");
		MyTask myTask2 = new MyTask();
		myTask2.setInfo("task-2");
		
		timer.schedule(myTask1, 1000, 2000);
		timer.scheduleAtFixedRate(myTask2, 2000, 3000);
		
		while (true) {
			try {
				Scanner sc = new Scanner(System.in);
				String state = sc.next();
				//当接收到的字符串时  cancel_1  时,停止  myTask1 任务
				if(state.equals("cancel_1")){
					myTask1.cancel();
				}
				//当接收到的字符串时  cancel_2  时,停止  myTask2 任务
				else if(state.equals("cancel_2")){
					myTask2.cancel();
					
				//当接收到的字符串时  cancel_all  时,停止  所有任务	
				}else if(state.equals("cancel_all")){
					timer.cancel();
					break;
				}
				//当接受到开头是  task_1 的字符串,替换 myTask1实体
				if(state.startsWith("task_1")){
					myTask1.setInfo(state);
				//当接受到开头是  task_1 的字符串,替换 myTask2实体
				}else if(state.startsWith("task_2")){
					myTask2.setInfo(state);
				}
			
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 定时任务实体
	 * @author Administrator
	 *
	 */
	static class MyTask extends TimerTask {
		String info = "";

		public void run() {
			System.out.println(info);
		}
		public String getInfo() {
			return info;
		}
		public void setInfo(String info) {
			this.info = info;
		}
	}
}

但是我们在应用场景中会遇到每一个任务的执行时间都不相同,并且每一个任务只执行一次,如果按照上面的做法,就是每次生成一个TimerTask放到Timer中执行,这样太耗费资源了,我们需要实现一个线程来监听所有的任务。

public class TimerTest2 extends Thread {

	private static long TIME_OUT = 10000;// 每一个任务在定时器中的超时时间
	// 任务列表,线程安全
	private static List<MyTask> myTasks = Collections
			.synchronizedList(new ArrayList<MyTask>());

	public void run() {
		while (true) {
			// 同步
			synchronized (myTasks) {
				if (myTasks.size() > 0) {

					MyTask myTask = myTasks.get(0);
					long flagTime = TIME_OUT
							- (new Date().getTime() - myTask.getDate()
									.getTime());
					// 获取第一个任务,并且判断该任务是否超时,如果是,删除该任务
					if (flagTime < 0) {
						myTasks.remove(myTask);
					} else {
						try {
							// 如果该任务没有超时,继续等待时间
							myTasks.wait(flagTime);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				} else {
					try {
						myTasks.wait();// 如果列表为空,那么就一直休眠
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}

	/**
	 * 添加新的任务
	 * 
	 * @param info
	 */
	public void addTask(String info) {

		// 创建新的任务
		MyTask myTask = new MyTask();
		myTask.setDate(new Date());
		myTask.setInfo(info);
		// 同步
		synchronized (myTasks) {
			// 将任务添加到任务列表中,并且唤醒线程
			myTasks.add(myTask);
			myTasks.notify();
		}
	}

	
	/**
	 * 检查该任务是否存在
	 * @param info
	 * @return
	 */
	public boolean checkTask(String info) {
		synchronized (myTasks) {
			//遍历任务列表,判断该任务是否存在
			for (MyTask myTask : myTasks) {
				if (myTask.getInfo().equals(info)) {
					return true;
				}
			}
			return false;
		}
	}
	
	
	public static void main(String[] args) {
		TimerTest2 timerTest2 = new TimerTest2();
		timerTest2.start();//启动线程
		
		timerTest2.addTask("task");
		
		try {
			Thread.sleep(5000);
			System.out.println("当前过了5秒,任务  task 是否存在 :" + timerTest2.checkTask("task"));
			
			Thread.sleep(6000);
			System.out.println("当前过了11秒,任务  task 是否存在 :" + timerTest2.checkTask("task"));
			
			
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
	}
	
	

	/**
	 * 任务实体类
	 * @author Administrator
	 *
	 */
	static class MyTask {
		String info;
		Date date;//任务实体生成时间

		public String getInfo() {
			return info;
		}
		public void setInfo(String info) {
			this.info = info;
		}
		public Date getDate() {
			return date;
		}
		public void setDate(Date date) {
			this.date = date;
		}

	}

}

从以上程序可以看出,每个任务(MyTask) 都放置了一个date(生成实体对象的时间),然后设置每一个任务的超时时间为10秒。任务是以链表的形式存放的,在run方法中,当任务链表中没有任务时,永久休眠,添加新的任务时,唤醒线程,线程中判断该任务是否超时,如果不超时计算出超时时间,并且休眠,如果超时,则删除该任务。

以上程序可以继续扩展,可以将超时时间放到任务实体中,做到完全控制任务的运行时间


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值