java 线程池使用_线程池ScheduledExecutorService使用

27d808b5fabfc0d850b05a6a9cac0719.gif     阅读本文约需要5分钟 

大家好,我是你们的导师,经常看我朋友圈的同学应该知道,我每天会在微信上给大家免费提供以下服务!

1、长期为你提供最优质的学习资源!

2、给你解决技术问题!

3、每天在朋友圈里分享优质的技术文章!

4、每周1、3、5送纸质书籍免费送给大家,每年至少送书800本书!

5、为大家推荐靠谱的就业单位!

请注意!我上面说的5点全部都是免费的!全网你应该找不到第二家吧!

当然,大家在我私人微信上问我问题,仅限回答web前端、java相关的。

---------------------------

好了,接下来开始今天的技术分享!上次老师跟大家分享了线程池ThreadPoolExecutor类使用的知识,今天跟大家分享下线程池ScheduledExecutorService使用的知识。

Executor 结构图

e70c8cb9d87338fa128ceb0b9561e660.png

ScheduledExecutorService是什么?

ScheduledExecutorService接口是netty事件循环组(eventLoop)实现的顶级接口,因此需要对该接口有较为深入的理解才能较为更好的理解netty的事件循环组。ScheduledExecutorService接口是java线程池中最重要的几个接口之一。它除了支持原生线程池的功能之外,同时支持定时任务处理的功能。

public interface ScheduledExecutorService extends ExecutorService 可安排在给定的延迟后运行或定期执行的命令。schedule 方法使用各种延迟创建任务,并返回一个可用于取消或检查执行的任务对象scheduleAtFixedRate 和 scheduleWithFixedDelay 方法创建并执行某些在取消前一直定期运行的任务所有的 schedule 方法都接受相对延迟和周期作为参数,而不是绝对的时间或日期SheduleExecutorService 是JDK 1.5出来的,比以前的Timer性能好

7cb6aa41632f2492769328e1d30a81cd.png

在JDK中为它提供了一个默认的实现类:ScheduledThreadPoolExecutor。下面我们来看它的基本用法。

ScheduledExecutorService的使用

ScheduledExecutorService包括三个方法:schedule()、scheduleAtFixedRate()、scheduleWithFixedDelay()。下面主要分析ScheduledThreadPoolExecutor实现类的使用。

schedule方法的实现原理

d1d628c99448c4f9413424c92aed4078.png

scheduleAtFixedRate()和scheduleWithFixedDelay()实现原理bf221fbbc5f2c24a868a600bba27a05f.png

1.schedule()方法

下面将演示该方法的基本使用,以及通过实验得出的结论,具体的实现原理后面分析。先来看几个例子。

例子1:public static void main(String[] args) {        // 注意此处线程个数为1        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);        long start = System.currentTimeMillis();        System.out.println("第一次提交");        executorService.schedule(()->{            System.out.println(System.currentTimeMillis() - start);            try {                // 注意此处休眠4秒                Thread.sleep(4000);            } catch (InterruptedException e) {                e.printStackTrace();            }        }, 3, TimeUnit.SECONDS);        System.out.println("第二次提交");        executorService.schedule(()->{            System.out.println(System.currentTimeMillis() - start);        }, 3, TimeUnit.SECONDS);}
输出:第一次提交第二次提交31147115
例子2:public static void main(String[] args) {        // 相较于例子1,这里的线程池改为2        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2);        long start = System.currentTimeMillis();        System.out.println("第一次提交");        executorService.schedule(()->{            System.out.println(System.currentTimeMillis() - start);            try {                // 注意此处休眠4秒                Thread.sleep(4000);            } catch (InterruptedException e) {                e.printStackTrace();            }        }, 3, TimeUnit.SECONDS);        System.out.println("第二次提交");        executorService.schedule(()->{            System.out.println(System.currentTimeMillis() - start);        }, 3, TimeUnit.SECONDS);}
输出:第一次提交第二次提交31673169
例子3public static void main(String[] args) {        // 注意这里的线程池个数改为1了        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);        long start = System.currentTimeMillis();        System.out.println("第一次提交");        executorService.schedule(()->{            System.out.println(System.currentTimeMillis() - start);            try {                // 注意此处休眠4秒                Thread.sleep(4000);            } catch (InterruptedException e) {                e.printStackTrace();            }        }, 3, TimeUnit.SECONDS);        System.out.println("第二次提交");        // 注意此处延迟时间改为2s        executorService.schedule(()->{            System.out.println(System.currentTimeMillis() - start);        }, 2, TimeUnit.SECONDS);}
输出:第一次提交第二次提交21033100

结果分析:

1.例子1中,线程池大小1,第一次提交的任务成功延迟3s执行,并且执行耗时为4s。而第二次提交的任务延迟7s后才执行,不符合3s延迟的预期。

2.例子2中,线程池大小2,第一次和第二次提交的任务都延迟3s执行,符合预期。说明当有多个任务提交的时候,延迟执行与线程池的大小和上一个任务执行耗时两个因素有关。

3.例子3中,线程池大小1,第一次提交的任务延迟3s执行,第二次提交的任务延迟2s执行。说明提交任务的先后顺序与实际执行的顺序无关。

结论:起到延迟执行的作用;多次提交任务时,后面任务延迟执行的时间是否准确,与线程池的大小和上一个任务执行耗时两个因素有关。提交任务的先后顺序与实际执行的顺序无关,而是与延迟时间有关。

2.scheduleAtFixedRate()方法

scheduleAtFixedRate()方法比起前面的schedule()方法复杂得多,这里就不再分析提交多个任务的情况,等到讲解了他们的实现原理之后,再根据原理分析即可。同样先演示其基本用法,再根据输出分析结论。

例子1public static void main(String[] args) {        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);        executorService.scheduleAtFixedRate(()->{            System.out.println("coming");            try {                // 注意此处休眠时间为2s                Thread.sleep(2000);                System.out.println("sleep end");            } catch (InterruptedException e) {                e.printStackTrace();            }        // 延迟0s执行,周期为3s        }, 0, 3, TimeUnit.SECONDS);}
例子2public static void main(String[] args) {        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);        executorService.scheduleAtFixedRate(()->{            System.out.println("coming");            try {                // 注意此处休眠时间为5s                Thread.sleep(5000);                System.out.println("sleep end");            } catch (InterruptedException e) {                e.printStackTrace();            }        // 延迟0s执行,周期为3s        }, 0, 3, TimeUnit.SECONDS);}

先到IDE跑这两个例子,我们可以发现。

结果分析:例子1中,任务正常的每3s周期性执行;例子2中,每个任务执行耗时为5s,而我们预期的是周期3s执行一次。但事实上是需要等待上一个周期执行完毕,下一个周期马上执行。也就是5s执行一次。

结论:此方法用于周期性执行任务。当任务耗时长于周期,那么下一个周期任务将在上一个执行完毕之后马上执行。当任务耗时短于周期,那么正常周期性执行。

3.scheduleWithFixedDelay()方法

例子1public static void main(String[] args) {        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);        executorService.scheduleWithFixedDelay(()->{            System.out.println("coming");            try {                // 注意此处休眠时间为2s                Thread.sleep(2000);                System.out.println("sleep end");            } catch (InterruptedException e) {                e.printStackTrace();            }        // 第一个任务延迟0s执行,其余延迟为3s        }, 0, 3, TimeUnit.SECONDS);}例子2public static void main(String[] args) {        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);        executorService.scheduleWithFixedDelay(()->{            System.out.println("coming");            try {                // 注意此处休眠时间为5s                Thread.sleep(5000);                System.out.println("sleep end");            } catch (InterruptedException e) {                e.printStackTrace();            }        // 第一个任务延迟0s执行,其余延迟为3s        }, 0, 3, TimeUnit.SECONDS);}

到IDE跑这两个例子。

结果分析:例子1中,第二次执行等到上一次执行完毕之后,延迟3s才执行。例子2中,也是一样。

结论:此方法用于周期性执行;无论上一个方法耗时多长,下一个方法都会等到上一个方法执行完毕之后,再经过delay的时间才执行。

今天就分享这么多,关于线程池ScheduledExecutorService使用,你学会了多少欢迎在留言区评论,对于有价值的留言,我们都会一一回复的。如果觉得文章对你有一丢丢帮助,请点右下角【在看】,让更多人看到该文章。

b5d5e0f016bc52fd5eea675a558a71a9.gif

dcaefc0f42638859fb8109bba4f5b525.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值