[笔记][Java7并发编程实战手册]4.7-4.8 在执行器中延迟执行或则周期执行任务ScheduledThreadPoolExecutor

[笔记][Java7并发编程实战手册]系列目录


看这本书到现在这个章节。我总算是发现了。有些时候一个方法都会开一个章节来讲解。而且还没有什么好东西。
以后要是再有类似的章节。我就直接合在一起得了。


简介

  newScheduledThreadPool:创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。
它可以实现延迟或则周期执行任务。
在线程池中,发送一个任务,线程池会按照配置尽快的执行这个任务,当任务完成,将会从执行器中删除,如果需要再次执行该任务,就得再次发送该任务给线程池执行器。但是newScheduledThreadPool可以做到周期执行。
这里写图片描述


本章newScheduledThreadPool使用心得

  1. 本章的实现类ScheduledThreadPoolExecutor是ThreadPoolExecutor的子类
  2. 延迟要使用schedule方法,立即运行使用execute方法
  3. shutdown()不会阻塞等待任务结束,只是发起一个有序任务的关闭,并且不接受新的任务。想要达到使用它来等待所有任务的结束阻塞。需要配合使用awaitTermination
  4. awaitTermination(long timeout,TimeUnit unit):最长阻塞指定的时间,如果在这之前发生了:执行器关闭,线程中断,都不会按照指定的时间继续阻塞等待。只要所有任务完成则不会继续阻塞。
  5. scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit):周期执行:意思是:提交一个runnable任务给执行器,在initialDelay时间后开始执行该任务,以后每隔period时间重复执行,但是如果任务执行时间不间隔时间长,将会被延迟执行,而不是间隔时间到了就同时执行线程任务,如果发生了异常,后续任务将被取消
  6. 周期执行任务,没有返回结果,也不能关闭执行器,否则任务就会被取消了,不会执行;
  7. 周期执行任务,任务间隔时间小于任务的执行时间的话,任务将被延迟执行,也就是说如果任务间隔时间小于任务执行时间的话,只有上一个任务执行完成了,下一个才会被执行()
  8. scheduleWithFixedDelay 和 scheduleAtFixedRate :如果不仔细看光看api的话,还真看不出来有什么区别:他们唯一的区别是:
    scheduleWithFixedDelay 的第三个参数是:两次任务结束和任务开始之间的间隔
    scheduleAtFixedRate 的第三个参数是:两次任务开始之间的间隔时间
    我刚开始看到这个解释的时候也蒙了:在任务间隔时间 小于 任务执行时间的情况下能看出这两个方法的差别。在这个场景下,scheduleAtFixedRate 的任务时间间隔就相当于没有了,上一个任务完成下一个任务马上开始。而scheduleWithFixedDelay 始终保持两次任务之间的间隔,就算上一次的任务比间隔时间大,但是下一次的任务开始之前还是有间隔时间的。

示例

延迟执行

场景描述:很简单的一个例子,怎么让任务延迟执行,纠正了之前的错误理解

/**
 * Created by zhuqiang on 2015/8/31 0031.
 */
public class Client {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ScheduledThreadPoolExecutor stp = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(1);
        ArrayList<ScheduledFuture<String>> list = new ArrayList<ScheduledFuture<String>>();  //存放异步获取结果对象

        for (int i = 0; i < 5; i++) {
            ScheduledFuture<String> schedule = stp.schedule(new Task("小强" + i), i, TimeUnit.SECONDS);//循环5次,并设定每个任务延迟执行的时间,单位为秒
            list.add(schedule);
        }

        stp.shutdown();// 纠正一下,该方法不会阻塞当前线程,只是会等到所有任务完成后,才关闭执行器。

        /**
         * awaitTermination : 的意思是,按指定的时间阻塞当前线程,在超时前都会阻塞,或则未超时,但是执行器关闭,会阻塞到所有任务完成。
         * 下面的代码是:最长阻塞1天,如果在这之前发生了:执行器关闭,线程中断,都不会按照指定的时间继续等待一天。只要所有任务完成则不会继续阻塞
         */
        stp.awaitTermination(1, TimeUnit.DAYS);  // jsdkApi解释:请求关闭、发生超时或者当前线程中断,无论哪一个首先发生之后,都将导致阻塞,直到所有任务完成执行。
        System.out.println("-------  所有任务已完成");
        for (ScheduledFuture<String> s : list) {
            System.out.println(s.get());
        }
    }
}

class Task implements Callable<String> {
    private String name;

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

    @Override
    public String call() throws Exception {
        System.out.printf("%s,延迟执行任务 %s,时间:%s\n", Thread.currentThread().getName(), name, new Date());
        return name;
    }
}

某一次运行结果:

pool-1-thread-1,延迟执行任务 小强0,时间:Mon Aug 31 21:29:55 CST 2015
pool-1-thread-1,延迟执行任务 小强1,时间:Mon Aug 31 21:29:56 CST 2015
pool-1-thread-1,延迟执行任务 小强2,时间:Mon Aug 31 21:29:57 CST 2015
pool-1-thread-1,延迟执行任务 小强3,时间:Mon Aug 31 21:29:58 CST 2015
pool-1-thread-1,延迟执行任务 小强4,时间:Mon Aug 31 21:29:59 CST 2015
-------  所有任务已完成
小强0
小强1
小强2
小强3
小强4

结果说明:
  我们创建了一个线程池,5个任务,可以看到上面的运行结果,按照延迟时间来执行的。并且使用shutdown和awaitTermination来阻塞等待所有任务完成再打印任务结果。


周期执行

场景描述:就是一个很普通的例子,一个任务 来掩饰 周期性是怎么使用的。周期性的方法 没有返回结果了。

/**
 * Created by zhuqiang on 2015/8/31 0031.
 */
public class Client {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ScheduledThreadPoolExecutor stp = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(1);
        //提交给线程池执行器:提交一个任务,1秒后执行,每隔5秒执行一次
        ScheduledFuture<?> s = stp.scheduleAtFixedRate(new Task("小强"), 1, 5, TimeUnit.SECONDS);

//        stp.shutdown();
//        stp.awaitTermination(1, TimeUnit.DAYS);
        //这个周期性任务,没有返回结果了,而且。记得不要阻塞等待任务结果。也不要关闭执行器,否则,你会看到:把下面的打印完了。都没有执行线程里面的内容
        for (int i = 0; i < 10; i++) {
            System.out.println("该任务离下一次执行时间(秒):" + s.getDelay(TimeUnit.SECONDS));
            TimeUnit.SECONDS.sleep(2); //休眠两秒看到更准确的时间
        }
    }
}

/**
 * 周期执行不能使用Callable了
 */
class Task implements Runnable {
    private String name;

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

    @Override
    public void run() {
        System.out.printf("%s,延迟执行任务 %s,时间:%s\n", Thread.currentThread().getName(), name, new Date());
    }


}

某一次的执行结果:

该任务离下一次执行时间(秒):0
pool-1-thread-1,延迟执行任务 小强,时间:Mon Aug 31 21:58:32 CST 2015
该任务离下一次执行时间(秒):3
该任务离下一次执行时间(秒):1
该任务离下一次执行时间(秒):0
pool-1-thread-1,延迟执行任务 小强,时间:Mon Aug 31 21:58:37 CST 2015
该任务离下一次执行时间(秒):2
该任务离下一次执行时间(秒):0
pool-1-thread-1,延迟执行任务 小强,时间:Mon Aug 31 21:58:42 CST 2015
该任务离下一次执行时间(秒):3
该任务离下一次执行时间(秒):1
pool-1-thread-1,延迟执行任务 小强,时间:Mon Aug 31 21:58:47 CST 2015
该任务离下一次执行时间(秒):4
该任务离下一次执行时间(秒):2
pool-1-thread-1,延迟执行任务 小强,时间:Mon Aug 31 21:58:52 CST 2015
pool-1-thread-1,延迟执行任务 小强,时间:Mon Aug 31 21:58:57 CST 2015
pool-1-thread-1,延迟执行任务 小强,时间:Mon Aug 31 21:59:02 CST 2015
pool-1-thread-1,延迟执行任务 小强,时间:Mon Aug 31 21:59:07 CST 2015

周期执行:演示一个特性:间隔周期之间时间如果小于任务执行时间,则会延迟执行任务

/**
 * Created by zhuqiang on 2015/8/31 0031.
 */
public class Client {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ScheduledThreadPoolExecutor stp = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(2);
        //提交给线程池执行器:提交一个任务,1秒后执行,每隔5秒执行一次
        ScheduledFuture<?> s = stp.scheduleAtFixedRate(new Task("小强"), 1, 5, TimeUnit.SECONDS);
//        ScheduledFuture<?> s = stp.scheduleWithFixedDelay(new Task("小强"), 1, 5, TimeUnit.SECONDS); //这个方法和上面的方法的唯一区别就是:第三个参数不同
        //这个周期性任务,没有返回结果了,而且。记得不要阻塞等待任务结果。也不要关闭执行器,否则,你会看到:把下面的打印完了。都没有执行线程里面的内容
        for (int i = 0; i < 10; i++) {
            System.out.println("该任务离下一次执行时间(秒):" + s.getDelay(TimeUnit.SECONDS));
            TimeUnit.SECONDS.sleep(2); //休眠两秒看到更准确的时间
        }
    }
}

/**
 * 周期执行不能使用Callable了
 */
class Task implements Runnable {
    private String name;

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

    @Override
    public void run() {
        System.out.printf("%s,延迟执行任务 %s,时间:%s\n", Thread.currentThread().getName(), name, new Date());
        //演示1:scheduleAtFixedRate方法,任务执行周期大于5秒。看效果。任务是不会同时执行的
        try {
            TimeUnit.SECONDS.sleep(6);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

某一次的运行结果(手动终止的):

该任务离下一次执行时间(秒):0
pool-1-thread-1,延迟执行任务 小强,时间:Mon Aug 31 22:15:51 CST 2015
该任务离下一次执行时间(秒):-1
该任务离下一次执行时间(秒):-3
该任务离下一次执行时间(秒):-5
pool-1-thread-1,延迟执行任务 小强,时间:Mon Aug 31 22:15:57 CST 2015
该任务离下一次执行时间(秒):-2
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值