线程执行者(七)执行者延迟运行一个任务

声明:本文是《 Java 7 Concurrency Cookbook 》的第四章,作者: Javier Fernández González     译者:许巧辉     校对:方腾飞,叶磊

执行者延迟运行一个任务

执行者框架提供ThreadPoolExecutor类,使用池中的线程来执行Callable和Runnable任务,这样可以避免所有线程的创建操作。当你提交一个任务给执行者,会根据执行者的配置尽快执行它。在有些使用情况下,当你对尽快执行任务不感觉兴趣。你可能想要在一段时间之后执行任务或周期性地执行任务。基于这些目的,执行者框架提供 ScheduledThreadPoolExecutor类。

在这个指南中,你将学习如何创建ScheduledThreadPoolExecutor和如何使用它安排任务在指定的时间后执行。

准备工作…

这个指南的例子使用Eclipse IDE实现。如果你使用Eclipse或其他IDE,如NetBeans,打开它并创建一个新的Java项目。

如何做…

按以下步骤来实现的这个例子:

1.创建Task类,实现Callable接口,参数化为String类型。


public class Task implements Callable<String> {

2.声明一个私有的、类型为String、名为name的属性,用来存储任务的名称。


private String name;

3.实现Task类的构造器,初始化name属性。


public Task(String name) {
this.name=name;
}

4.实现call()方法,写入实际日期到控制台,返回一个文本,如:Hello, world。


public String call() throws Exception {
System.out.printf("%s: Starting at : %s/n",name,new Date());
return "Hello, world";
}

5.实现示例的主类,创建Main类,实现main()方法。


public class Main {
public static void main(String[] args) {

6.使用Executors类的newScheduledThreadPool()方法,创建ScheduledThreadPoolExecutor类的一个执行者。传入参数1。


ScheduledThreadPoolExecutor executor=(ScheduledThreadPoolExecutor)Executors.newScheduledThreadPool(1);

7.使用ScheduledThreadPoolExecutor实例的schedule()方法,初始化和开始一些任务(本例中5个任务)。


System.out.printf("Main: Starting at: %s/n",new Date());
for (int i=0; i<5; i++) {
Task task=new Task("Task "+i);
executor.schedule(task,i+1 , TimeUnit.SECONDS);
}

8.使用shutdown()方法关闭执行者。


executor.shutdown();

9.使用执行者的awaitTermination()方法,等待所有任务完成。


try {
executor.awaitTermination(1, TimeUnit.DAYS);
} catch (InterruptedException e) {
e.printStackTrace();
}

10.写入一条信息表明程序结束时间。


System.out.printf("Main: Ends at: %s/n",new Date());

它是如何工作的…

在这个示例中,关键的一点是Main类和ScheduledThreadPoolExecutor的管理。正如使用ThreadPoolExecutor类创建预定的执行者,Java建议利用Executors类。在本例中,你使用newScheduledThreadPool()方法。你用1作为参数传给这个方法。这个参数是你想要让线程池创建的线程数。

你必须使用schedule()方法,让执行者在一段时间后执行任务。这个方法接收3个参数,如下:

  • 你想要执行的任务
  • 你想要让任务在执行前等待多长时间
  • 时间单位,指定为TimeUnit类的常数

在本例中,每个任务等待的秒数(TimeUnit.SECONDS)等于它在任务数组中的位置再加1。

注意事项:如果你想在给定时间执行一个任务,计算这个日期与当前日期的差异,使用这个差异作为任务的延迟。

以下截图显示这个示例执行的输出:

5

你可以看出这些任务是如何开始执行的,一秒执行一个。所有任务都是同时提交给执行者的,但每个任务比之前的任务都有1秒的延迟。

不止这些…

你也可以使用Runnable接口实现任务,因为ScheduledThreadPoolExecutor类的schedule()方法接收这两种类型(Runnable和Callable)的任务。

尽管ScheduledThreadPoolExecutor类是ThreadPoolExecutor类的子类,因此,它继承 ThreadPoolExecutor类的所有功能,但Java建议使用ScheduledThreadPoolExecutor仅适用于调度任务。

最后,你可以配置ScheduledThreadPoolExecutor的行为,当你调用shutdown()方法时,并且有待处理的任务正在等待它们延迟结束。默认的行为是,不管执行者是否结束这些任务都将被执行。你可以使用ScheduledThreadPoolExecutor类的setExecuteExistingDelayedTasksAfterShutdownPolicy()方法来改变这种行为。使用false,调用 shutdown()时,待处理的任务不会被执行。

参见

  • 在第4章,线程执行者中的执行者执行返回结果的任务指南

原创文章,作者:kepupublish,如若转载,请注明出处:https://blog.ytso.com/140923.html

(0)
上一篇 2021年9月5日
下一篇 2021年9月5日

相关推荐

发表回复

登录后才能评论