并发编程:自定义并发类:5、自定义周期调度任务

本文介绍如何自定义ScheduledThreadPoolExecutor及其实现周期性任务的方法。通过继承ScheduledThreadPoolExecutor并重写关键方法,实现了对周期任务的自定义控制。此外,还提供了一个具体的任务执行示例。

目录

ScheduledThreadPoolExecutor

一、主程序

二、自定义周期线程池

三、自定义周期任务类

四、一个被执行的普通任务

五、执行结果


ScheduledThreadPoolExecutor

周期调度性线程池(Scheduled thread pool)是一个Executor框架的基本线程池的拓展。

  • 延迟任务(Delayed task):在一段时间后执行一次。(可执行Callable和Runnable对象)
  • 周期任务(Periodic task):在一段时间后,永久地周期性地执行。(只能执行Runnable对象)

一、主程序

package xyz.jangle.thread.test.n8_6.schedule;

import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * 	8.6、自定义在周期调度线程池中运行的任务类
 * @author jangle
 * @email jangle@jangle.xyz
 * @time 2020年9月25日 上午9:20:05
 * 
 */
public class M {

	public static void main(String[] args) throws Exception {
		// 使用自定义周期线程池
		MyScheduledThreadPoolExecutor executor = new MyScheduledThreadPoolExecutor(4);
		Task task = new Task();
		System.out.println("Main: " + new Date());
		executor.schedule(task, 1, TimeUnit.SECONDS);
		TimeUnit.SECONDS.sleep(6);
		task = new Task();
		System.out.println("Main:" + new Date());
		executor.scheduleAtFixedRate(task, 1, 3, TimeUnit.SECONDS);
		TimeUnit.SECONDS.sleep(10);
		executor.shutdown();
		executor.awaitTermination(1, TimeUnit.DAYS);
		System.out.println("Main:End of the program.");
	}

}

二、自定义周期线程池

package xyz.jangle.thread.test.n8_6.schedule;

import java.util.concurrent.RunnableScheduledFuture;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 *  自定义(继承重写)周期调度线程池
 * @author jangle
 * @email jangle@jangle.xyz
 * @time 2020年9月25日 下午3:15:44
 * 
 */
public class MyScheduledThreadPoolExecutor extends ScheduledThreadPoolExecutor {

	public MyScheduledThreadPoolExecutor(int corePoolSize) {
		super(corePoolSize);
	}

	@Override
	protected <V> RunnableScheduledFuture<V> decorateTask(Runnable runnable, RunnableScheduledFuture<V> task) {
		// 该方法会被 schedule、scheduleAtFixedRate、scheduleWithFixedDelay 方法内部调用
		// 这个方法的任务是对原任务进行包装。
		// 包装后的任务必须是实现RunnableScheduledFuture接口的类(因为线程池需要判断是否是周期任务)
		return new MyScheduledTask<V>(runnable, null, task, this);
	}

	@Override
	public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
		// scheduleAtFixedRate 方法会调用decorateTask方法,所以会返回MyScheduledTask类型的对象
		ScheduledFuture<?> task = super.scheduleAtFixedRate(command, initialDelay, period, unit);
		MyScheduledTask<?> myTask = (MyScheduledTask<?>) task;
		myTask.setPeriod(TimeUnit.MILLISECONDS.convert(period, unit));
		return myTask;
	}

}

三、自定义周期任务类

在周期调度执行器中执行的任务必须实现RunnableScheduledFuture接口并拓展FutureTask类。

package xyz.jangle.thread.test.n8_6.schedule;

import java.util.Date;
import java.util.concurrent.Delayed;
import java.util.concurrent.FutureTask;
import java.util.concurrent.RunnableScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 *  自定义在周期调度线程池中运行的任务类
 * @author jangle
 * @email jangle@jangle.xyz
 * @time 2020年9月25日 上午9:22:49
 * 
 */
public class MyScheduledTask<V> extends FutureTask<V> implements RunnableScheduledFuture<V> {
	// 原任务
	private RunnableScheduledFuture<V> task;
	// 线程池
	private ScheduledThreadPoolExecutor executor;
	// 运行周期
	private long period;
	// 用于周期任务(开始执行的时间)
	private long startDate;

	public MyScheduledTask(Runnable runnable, V result, RunnableScheduledFuture<V> task,
			ScheduledThreadPoolExecutor executor) {
		super(runnable, result);
		this.task = task;
		this.executor = executor;
	}

	@Override
	public long getDelay(TimeUnit unit) {
		if (!isPeriodic()) {
			return task.getDelay(unit);
		} else {
			if (startDate == 0) {
				return task.getDelay(unit);
			} else {
				var now = new Date();
				long delay = startDate - now.getTime();
				long res = unit.convert(delay, TimeUnit.MILLISECONDS);
//				System.out.println("******delay:" + delay + ",res" + res);
				return res;
			}
		}
	}

	@Override
	public int compareTo(Delayed o) {
		return task.compareTo(o);
	}

	@Override
	public boolean isPeriodic() {
		return task.isPeriodic();
	}

	@Override
	public void run() {
		if (isPeriodic() && (!executor.isShutdown())) {
			var now = new Date();
			startDate = now.getTime() + period;
			executor.getQueue().add(this);
		}
		System.out.println("MyScheduledTask-Pre:" + new Date());
		System.out.println("MyScheduledTask: 是否是周期性任务:" + isPeriodic());
		super.runAndReset();
		System.out.println("MyScheduledTask-Post:" + new Date());
		System.out.println("*************************");
	}

	public void setPeriod(long period) {
		this.period = period;
	}

}

四、一个被执行的普通任务

package xyz.jangle.thread.test.n8_6.schedule;

import java.util.concurrent.TimeUnit;

/**
 *  普通的任务
 * @author jangle
 * @email jangle@jangle.xyz
 * @time 2020年9月25日 下午4:02:28
 * 
 */
public class Task implements Runnable {

	@Override
	public void run() {
		System.out.println("Task: Begin.");
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("Task: End.");
	}

}

五、执行结果

Main: Sat Oct 03 09:23:16 CST 2020
MyScheduledTask-Pre:Sat Oct 03 09:23:17 CST 2020
MyScheduledTask: 是否是周期性任务:false
Task: Begin.
Task: End.
MyScheduledTask-Post:Sat Oct 03 09:23:19 CST 2020
*************************
Main:Sat Oct 03 09:23:22 CST 2020
MyScheduledTask-Pre:Sat Oct 03 09:23:23 CST 2020
MyScheduledTask: 是否是周期性任务:true
Task: Begin.
Task: End.
MyScheduledTask-Post:Sat Oct 03 09:23:25 CST 2020
*************************
MyScheduledTask-Pre:Sat Oct 03 09:23:26 CST 2020
MyScheduledTask: 是否是周期性任务:true
Task: Begin.
Task: End.
MyScheduledTask-Post:Sat Oct 03 09:23:28 CST 2020
*************************
MyScheduledTask-Pre:Sat Oct 03 09:23:29 CST 2020
MyScheduledTask: 是否是周期性任务:true
Task: Begin.
Task: End.
MyScheduledTask-Post:Sat Oct 03 09:23:31 CST 2020
*************************
Main:End of the program.

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值