继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Java Timer 到 Executors.newScheduledThreadPool 定时任务和周期任务

Caeser110
关注TA
已关注
手记 139
粉丝 30
获赞 154

前言

定时任务里肯定可以查到 Timer ,关于 Timer 的介绍,有很多很详细的,我这里打算对该类进行演进,先从这个最简单的定时工具讲起,逐步实现定时任务的功能,周期性任务计划,多任务周期性计划。

起因

起因是因为我现在的项目上有周期性日程计划,但是计划了时间却不能准确进行,于是我打算自己试试写一个,而且由于我对 Timer 和 Thread 不是很熟悉,所以打算一步步演进项目,先从小的步骤开始进行,计划步骤如下:
第一步:实现1秒执行一次,总共执行三次
第二步:设置时间,到期执行
第三步:设置三个时间,三个任务,到期都要执行,产生不同的log文件,然后周期化,先设置成每天,然后每周
第四步:如果有成千上万个任务,如果降低线程的使用率,目前的想法是给执行任务的先后任务排序,最先执行的,先计时
第五步:网页界面,按钮:开始任务,任务临时退出(任务还继续,但是系统需要关闭一次,希望下次启动系统时继续任务,很可能出现启动系统时,本该执行的任务错过了执行时间,记录日志)

代码

于是本篇先实现前两步。
第一步很简单代码如下:

public class TimerTest03 {
	Timer timer;
    public TimerTest03(){
        timer = new Timer();
        timer.schedule(new TimerTaskTest03(), 1000, 2000);        
    }
    public static void main(String[] args) {
        new TimerTest03();
    }
    public class TimerTaskTest03 extends TimerTask{
    	int count=0;
        @Override
        public void run() {
            Date date = new Date(this.scheduledExecutionTime());
            System.out.println("本次执行该线程的时间为:" + date);
            count++;
            if(count==3) {
            	this.cancel();
            }
        }
    }
}

第二步也不难,只需要知道:schedule(TimerTask task, Date time)-安排在指定的时间执行指定的任务。

public class TimeScheduleTask {
	Timer timer;

	public TimeScheduleTask(Date scheduledTime) {
		System.out.println("指定时间time=" + scheduledTime);
		timer = new Timer();
		timer.schedule(new TimerTaskTest(), scheduledTime);
	}
	public class TimerTaskTest extends TimerTask {
		@Override
		public void run() {
			System.out.println("指定时间执行线程任务...");
		}
	}
	public static void main(String[] args) {
		// 创建 Calendar 对象
		Calendar calendar = Calendar.getInstance();
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-M-d H:m:s");
		// 指定一个日期
		Date date;
		try {
			date = dateFormat.parse("2019-8-30 09:25:16");
			// 对 calendar 设置为 date 所定的日期
			calendar.setTime(date);
			new TimeScheduleTask(calendar.getTime());
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

优缺点

Timer 是基于绝对时间,对系统时间特别敏感,在现在的项目里都是对日期有要求的,所以绝对时间是没有问题的,但是 Timer 内部是单一线程的,发生异常就会终止全部任务,于是给出了一个比较优秀的解决办法,就是使用 ScheduledThreadPoolExecutor ,这样就可以支持多任务了。

ScheduledExecutorService scheduExec=Executors.newScheduledThreadPool(2);

我们可以看看官方的解释

public static ExecutorService newFixedThreadPool(int nThreads)
Creates a thread pool that reuses a fixed number of threads operating off a shared unbounded queue. 
Parameters:
nThreads - the number of threads in the pool
Returns:
the newly created thread pool
Throws:
IllegalArgumentException - if nThreads <= 0

整理

上面的代码只是演示,我们需要提取我们需要的部分,我们希望实现的功能有,指定一个开始日期,这个日期是实际的日期,也就是服务器的时间,然后开始一个任务,这个任务是周期性的。为了不再是控制台打印,我将任务的内容改为记录日志,这样可以方便记录时间和产生文字内容。
任务代码:

public class ScheduleTask extends Thread {
	public void run() {
		CaeLogger.WriteLog("ScheduleTask", "goo");
	}
}

周期性任务:

public class ScheduledExecutorTest {
	private ScheduledExecutorService scheduExec;
	private ScheduleTask myTask;

	ScheduledExecutorTest(long num) {
		this.scheduExec = Executors.newScheduledThreadPool(1);
		myTask = new ScheduleTask();
		scheduExec.scheduleAtFixedRate(myTask, 0, num, TimeUnit.MINUTES);
	}

	public void startTask() {
		myTask.start();
	}

	public void endTask() {
		// 关闭具体任务线程
		myTask.interrupt();
		// 关闭周期计划
		scheduExec.shutdown();
	}
}

为了方便我做测试,我把改任务的周期设置为固定值,而且是每隔一分钟执行一次。下面是开始时间和结束时间主类:

public class TimeScheduleTask {
	Timer timer;
	Timer timerEnd;
	ScheduledExecutorTest myTask;
	TimerTaskTest1 timerF;

	public TimeScheduleTask(Date startTime, Date endTime) {
		System.out.println("指定时间time=" + startTime);
		CaeLogger.WriteLog("startTie", "XX");

		timer = new Timer();
		timerEnd = new Timer();
		timerF = new TimerTaskTest1();

		timer.schedule(timerF, startTime);
		timerEnd.schedule(new TimerTaskTest2(), endTime);

	}

	public class TimerTaskTest1 extends TimerTask {
		@Override
		public void run() {
			myTask = new ScheduledExecutorTest(1);
			myTask.startTask();
		}
	}

	public class TimerTaskTest2 extends TimerTask {
		@Override
		public void run() {
			if (myTask != null) {
				myTask.endTask();
				timerF.cancel();
				this.cancel();
			}

		}
	}

	public static void main(String[] args) {
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-M-d H:m:s");
		// 指定一个日期
		Date date;
		Date date1;
		try {
			date = dateFormat.parse("2019-8-30 14:54:00");
			date1 = dateFormat.parse("2019-8-30 14:59:00");
			new TimeScheduleTask(date, date1);

		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

结果:记录已产生,而且是到结束时间就停止了看图
在这里插入图片描述

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP