目录
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.

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

被折叠的 条评论
为什么被折叠?



