我是靠谱客的博主 热情绿茶,这篇文章主要介绍ScheduledExecutorService使用之——重复创建停止周期性任务,现在分享给大家,希望可以做个参考。

ScheduledExecutorService的创建就不用多说,直接上代码

复制代码
1
executorService = Executors.newSingleThreadScheduledExecutor();

ScheduledExecutorService的停止有shutdown和shutdownNow之分,可以看下它们之间的区别,但多数情况下都不能结束在线程池中的任务。不过有个小技巧可以让真正的逻辑不执行,就是在run方法中添加条件判断。如下:

复制代码
1
2
3
4
5
6
@Override public void run() { if (mFrag.mWifi != null) { //添加条件判断,在shutdown之前把mWifi置为空 mFrag.search(); //这样虽不能取消run方法的执行,但可以让真正的searchWifi逻辑不执行 } }

但是如果我们有业务需要,要求定时任务可以取消,再创建,该如何操作呢?

常规的写法就是

executorService.shutdownNow(); //取消
executorService.scheduleAtFixedRate(new Executor(),30,30, TimeUnit.SECONDS); //开始

坑1:

这样的话,熟悉的同学就知道会发生RejectedExecutionException异常。因为executorService已经关闭了。如果需要继续开始任务,则需要重新new 对象Executors.newSingleThreadScheduledExecutor()。

 

坑2:

在坑1的基础上,我们想想会发生什么。坑1取消事件调用的是shutdownNow方法,开始事件是newSingleThreadScheduledExecutor创建对象后,再scheduleAtFixedRate。这样的话,我们从log分析就可以看出来,任务可能多次执行,就是上一次任务并没有销毁。我们每开始一个任务前,就需要把上一次任务关闭、置空。像这样:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private void beginExecutorScan() { //先取消上一个任务,防止重复的任务 endExecutorScan(); executorService = Executors.newSingleThreadScheduledExecutor(); if (executorService != null) { Lg.e("ScheduledExecutorService beginExecutorScan"); executorService.scheduleAtFixedRate(new ScanScheduledExecutor(Frag.this),30,30, TimeUnit.SECONDS); } } private void endExecutorScan() { if(executorService != null) { Lg.e("ScheduledExecutorService endExecutorScan"); executorService.shutdownNow(); } executorService = null;//非单例模式,置空防止重复的任务 }

坑3:

如果定时任务执行过程中遇到发生异常,则后面的任务将不再执行。处理方式是在run中加try catch,这样当一个任务发生异常时,后续的任务还会继续执行。

 

解决完以上3种坑后,完整的可以重复开始、停止的ScheduledExecutorService周期性任务像这样:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
private void beginExecutorScan() { //先取消上一个任务,防止重复的任务 endExecutorScan(); executorService = Executors.newSingleThreadScheduledExecutor(); if (executorService != null) { Lg.e("ScheduledExecutorService beginExecutorScan"); executorService.scheduleAtFixedRate(new ScanScheduledExecutor(Frag.this),30,30, TimeUnit.SECONDS); } } private void endExecutorScan() { if(executorService != null) { Lg.e("ScheduledExecutorService endExecutorScan"); executorService.shutdownNow(); } executorService = null;//非单例模式,置空防止重复的任务 } //静态弱引用方式,防止内存泄露 static class ScanScheduledExecutor implements Runnable { WeakReference<Frag> mFragReference; ScanScheduledExecutor(Frag frag) { mFragReference = new WeakReference<>(frag); } @Override public void run() { try { final Frag mFrag = mFragReference.get(); if (mFrag == null) return; if (mFrag.mWifi != null) { //添加条件判断,在shutdown之前把mWifi置为空 mFrag.search(); //这样虽不能取消run方法的执行,但可以让真正的searchWifi逻辑不执行 } } catch (Exception e) { Lg.e("ScheduledExecutorService e:"+e.toString()); } } }

 

附:

scheduleAtFixedRate 与 scheduleWithFixedDelay 的区别:

scheduleAtFixedRate ,是以上一个任务开始的时间计时,N秒过去后,检测上一个任务是否执行完毕,如果上一个任务执行完毕,则当前任务立即执行,如果上一个任务没有执行完毕,则需要等上一个任务执行完毕后立即执行。

scheduleWithFixedDelay,是以上一个任务结束时开始计时,N秒过去后,立即执行。

 

最后

以上就是热情绿茶最近收集整理的关于ScheduledExecutorService使用之——重复创建停止周期性任务的全部内容,更多相关ScheduledExecutorService使用之——重复创建停止周期性任务内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(49)

评论列表共有 0 条评论

立即
投稿
返回
顶部