当前位置:嗨网首页>书籍在线阅读

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 对象。调用其父类的构造方法并存储 taskexecutor 字段:

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.创建一个名为 taskTask 对象,在控制台打印实际日期:

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");