18-案例实现
案例实现
根据如下步骤来实现本案例。
1.创建一个 MyScheduledTask
类。该类用于扩展 FutureTask
类以及实现 Runnable-ScheduledFuture
接口:
public class MyScheduledTask<V> extends FutureTask<V>
implements RunnableScheduledFuture<V> {
2.声明一个 RunnableScheduledFuture
类型的 task
私有字段:
private RunnableScheduledFuture<V> task;
3.声明一个 ScheduledThreadPoolExecutor
类型的 executor
私有字段:
private ScheduledThreadPoolExecutor executor;
4.声明一个 long
型的 period
私有字段:
private long period;
5.声明一个 long
型的 startDate
私有字段:
private long startDate;
6.实现该类一个构造方法。它将接收由一个任务执行的 Runnable
对象,而此任务返回的结果将用于创建 MyScheduledTask
对象的 RunnableScheduledFuture
任务以及将要执行任务的 ScheduledThreadPoolExecutor
对象。调用其父类的构造方法并存储 task
和 executor
字段:
public MyScheduledTask(Runnable runnable, V result,
RunnableScheduledFuture<V> task,
ScheduledThreadPoolExecutor executor) {
super(runnable, result);
this.task=task;
this.executor=executor;
}
7.实现 getDelay()
方法。如果任务是周期性的,并且 startDate
字段值不是零,则计算返回值作为 startDate
字段和实际日期之间的差值;否则,返回存储在 task
字段中的原始任务的延迟时间。不要忘记,必须将以时间单位形式返回的结果作为参数:
@Override
public long getDelay(TimeUnit unit) {
if (!isPeriodic()) {
return task.getDelay(unit);
} else {
if (startDate==0){
return task.getDelay(unit);
} else {
Date now=new Date();
long delay=startDate-now.getTime();
return unit.convert(delay, TimeUnit.MILLISECONDS);
}
}
}
8.实现 compareTo()
方法。调用原始任务的 compareTo()
方法:
@Override
public int compareTo(Delayed o) {
return task.compareTo(o);
}
9.实现 isPeriodic()
方法。调用原始任务的 isPeriodic()
方法:
@Override
public boolean isPeriodic() {
return task.isPeriodic();
}
10.实现 run()
方法。如果是周期性任务,则必须使用下一次任务的开始日期来更新 startDate
字段。将其计算为实际日期和时间段的总和。然后,再次将任务添加到 ScheduledThreadPoolExecutor
对象的队列中:
@Override
public void run() {
if (isPeriodic() && (!executor.isShutdown())) {
Date now=new Date();
startDate=now.getTime()+period;
executor.getQueue().add(this);
}
11.用实际日期向控制台打印消息。调用 runAndReset()
方法执行任务,然后使用实际日期将另一条消息打印到控制台:
System.out.printf("Pre-MyScheduledTask: %s\n",new Date());
System.out.printf("MyScheduledTask: Is Periodic: %s\n",
isPeriodic());
super.runAndReset();
System.out.printf("Post-MyScheduledTask: %s\n",new Date());
}
12.实现 setPeriod()
方法来建立此任务的时间段:
public void setPeriod(long period) {
this.period=period;
}
13.创建一个 MyScheduledThreadPoolExecutor
类来实现执行 MyScheduled-Task
任务的 ScheduledThreadPoolExecutor
对象。指定该类扩展 ScheduledThread-PoolExecutor
类:
public class MyScheduledThreadPoolExecutor extends
ScheduledThreadPoolExecutor {
14.实现一个只调用其父类构造方法的构造方法:
public MyScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize);
}
15.实现 decorateTask()
方法。它将接收要作为参数来执行的 Runnable
对象和此 Runnable
对象的 RunnableScheduledFuture
任务。用这些对象创建并返回 MyScheduledTask
任务来构造它们:
@Override
protected <V> RunnableScheduledFuture<V> decorateTask(
Runnable runnable,
RunnableScheduledFuture<V> task) {
MyScheduledTask<V> myTask=new MyScheduledTask<V>(runnable,
null, task,this);
return myTask;
}
16.重写 scheduleAtFixedRate()
方法。调用其父类的方法将返回的对象转换为 MyScheduledTask
对象,并用 setPeriod()
方法建立该任务的周期:
@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay, long period, TimeUnit unit) {
ScheduledFuture<?> task= super.scheduleAtFixedRate(command,
initialDelay, period, unit);
MyScheduledTask<?> myTask=(MyScheduledTask<?>)task;
myTask.setPeriod(TimeUnit.MILLISECONDS.convert(period,unit));
return task;
}
17.创建一个名为 Task
的类来实现 Runnable
接口:
public class Task implements Runnable {
18.实现 run()
方法。在任务开始时打印一条消息,将当前线程休眠2s,并在任务结束时打印另一条消息:
@Override
public void run() {
System.out.printf("Task: Begin.\n");
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("Task: End.\n");
}
19.实现本案例的主类,新建 Main
类和 main()
方法:
public class Main {
public static void main(String[] args) throws Exception{
20.创建一个名为executor的 MyScheduledThreadPoolExecutor
对象。用4作为参数以设置线程池中有两个线程:
MyScheduledThreadPoolExecutor executor=new
MyScheduledThreadPoolExecutor(4);
21.创建一个名为 task
的 Task
对象,在控制台打印实际日期:
Task task=new Task();
System.out.printf("Main: %s\n",new Date());
22.用 schedule()
方法将延迟任务发送给执行器。任务将在延迟1s后执行:
executor.schedule(task, 1, TimeUnit.SECONDS);
23.让主线程休眠3s:
TimeUnit.SECONDS.sleep(3);
24.创建另一个 Task
对象,再次在控制台中打印实际日期:
task=new Task();
System.out.printf("Main: %s\n",new Date());
25.用 scheduleAtFixedRate()
方法将周期性任务发送给执行器。该任务将在延迟1s后执行,然后每3s执行一次:
executor.scheduleAtFixedRate(task, 1, 3, TimeUnit.SECONDS);
26.让主线程休眠10s:
TimeUnit.SECONDS.sleep(10);
27.用 shutdown()
方法关闭执行器。用 awaitTermination()
方法等待执行器完成:
executor.shutdown();
executor.awaitTermination(1, TimeUnit.DAYS);
28.在控制台打印一条消息,以示程序结束:
System.out.printf("Main: End of the program.\n");