当前位置:   article > 正文

ScheduledExecutorService使用之——重复创建停止周期性任务_scheduledexecutorservice shutdown

scheduledexecutorservice shutdown

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

executorService = Executors.newSingleThreadScheduledExecutor();

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

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

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

常规的写法就是

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

坑1:

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

 

坑2:

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

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

坑3:

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

 

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

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

 

附:

scheduleAtFixedRate 与 scheduleWithFixedDelay 的区别:

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

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

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/83653
推荐阅读
  

闽ICP备14008679号