当前位置:   article > 正文

计划任务ScheduledExecutorService的使用总结

scheduledexecutorservice

Java中的计划任务Timer工具类提供了以计时器或计划任务的功能来实现按指定时间或时间间隔执行任务,但由于Timer工具类并不是以池pool,而是以队列的方式来管理线程的,所以在高并发的情况下运行效率较低,在新版JDK中提供了ScheduledExecutorService对象来解决效率与定时任务的功能。

 

1.ScheduledExecutorService的使用

类ScheduledExecutorService的主要作用就是可以将定时任务与线程池功能结合使用。实现类ScheduledThreadPoolExecutor的父接口还是Executor,父类是ThreadPoolExecutor,其部分方法是父类ThreadPoolExecutor提供并在子类ScheduledThreadPoolExecutor中重写的,比如submit()重载方法或shutdown()等方法。

2.ScheduledThreadPoolExecutor使用Callable延迟运行

使用Callable接口进行任务延迟运行的实验,具有返回值的功能。

  1. package mycallable;
  2. import java.util.concurrent.Callable;
  3. public class MyCallableA implements Callable<String> {
  4. @Override
  5. public String call() throws Exception {
  6. try {
  7. System.out.println("callA begin " + Thread.currentThread().getName() + " " + System.currentTimeMillis());
  8. Thread.sleep(3000);
  9. System.out.println("callA end " + Thread.currentThread().getName() + " " + System.currentTimeMillis());
  10. } catch (Exception e) {
  11. e.printStackTrace();
  12. }
  13. return "returnA";
  14. }
  15. }
  1. package mycallable;
  2. import java.util.concurrent.Callable;
  3. public class MyCallableB implements Callable<String> {
  4. @Override
  5. public String call() throws Exception {
  6. System.out.println("callB begin " + Thread.currentThread().getName() + " " + System.currentTimeMillis());
  7. System.out.println("callB end " + Thread.currentThread().getName() + " " + System.currentTimeMillis());
  8. return "returnB";
  9. }
  10. }
  1. package test.run;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import java.util.concurrent.Callable;
  5. import java.util.concurrent.ExecutionException;
  6. import java.util.concurrent.Executors;
  7. import java.util.concurrent.ScheduledExecutorService;
  8. import java.util.concurrent.ScheduledFuture;
  9. import java.util.concurrent.TimeUnit;
  10. import mycallable.MyCallableA;
  11. import mycallable.MyCallableB;
  12. public class Run1 {
  13. @SuppressWarnings("unchecked")
  14. public static void main(String[] args) {
  15. try {
  16. List<Callable> callableList = new ArrayList();
  17. callableList.add(new MyCallableA());
  18. callableList.add(new MyCallableB());
  19. // 调用方法newSingleThreadScheduledExecutor
  20. // 取得一个单任务的计划任务执行池
  21. ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
  22. ScheduledFuture<String> futureA = executor.schedule(callableList.get(0), 4L, TimeUnit.SECONDS);
  23. ScheduledFuture<String> futureB = executor.schedule(callableList.get(1), 4L, TimeUnit.SECONDS);
  24. System.out.println(" X=" + System.currentTimeMillis());
  25. System.out.println("返回值A:" + futureA.get());
  26. System.out.println("返回值B:" + futureB.get());
  27. System.out.println(" Y=" + System.currentTimeMillis());
  28. } catch (InterruptedException e) {
  29. e.printStackTrace();
  30. } catch (ExecutionException e) {
  31. e.printStackTrace();
  32. }
  33. }
  34. }
  1. package test.run;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import java.util.concurrent.Callable;
  5. import java.util.concurrent.ExecutionException;
  6. import java.util.concurrent.Executors;
  7. import java.util.concurrent.ScheduledExecutorService;
  8. import java.util.concurrent.ScheduledFuture;
  9. import java.util.concurrent.TimeUnit;
  10. import mycallable.MyCallableA;
  11. import mycallable.MyCallableB;
  12. public class Run2 {
  13. public static void main(String[] args) {
  14. try {
  15. List<Callable> callableList = new ArrayList();
  16. callableList.add(new MyCallableA());
  17. callableList.add(new MyCallableB());
  18. // 调用方法newScheduledThreadPool(corePoolSize >1)
  19. // 取得一个同时运行corePoolSize任务个数的计划任务执行池
  20. ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
  21. ScheduledFuture<String> futureA = executor.schedule(callableList.get(0), 4L, TimeUnit.SECONDS);
  22. ScheduledFuture<String> futureB = executor.schedule(callableList.get(1), 4L, TimeUnit.SECONDS);
  23. System.out.println(" X=" + System.currentTimeMillis());
  24. System.out.println("返回值A:" + futureA.get());
  25. System.out.println("返回值B:" + futureB.get());
  26. System.out.println(" Y=" + System.currentTimeMillis());
  27. } catch (InterruptedException e) {
  28. e.printStackTrace();
  29. } catch (ExecutionException e) {
  30. e.printStackTrace();
  31. }
  32. }
  33. }
  1. package test.run;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import java.util.concurrent.Callable;
  5. import java.util.concurrent.ExecutionException;
  6. import java.util.concurrent.Executors;
  7. import java.util.concurrent.ScheduledExecutorService;
  8. import java.util.concurrent.ScheduledFuture;
  9. import java.util.concurrent.TimeUnit;
  10. import mycallable.MyCallableA;
  11. import mycallable.MyCallableB;
  12. public class Run3 {
  13. public static void main(String[] args) {
  14. try {
  15. List<Callable> callableList = new ArrayList();
  16. callableList.add(new MyCallableA());
  17. callableList.add(new MyCallableB());
  18. // 调用方法newScheduledThreadPool(1)
  19. // 取得一个单任务的计划任务执行池
  20. ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
  21. ScheduledFuture<String> futureA = executor.schedule(callableList.get(0), 4L, TimeUnit.SECONDS);
  22. ScheduledFuture<String> futureB = executor.schedule(callableList.get(1), 4L, TimeUnit.SECONDS);
  23. System.out.println(" X=" + System.currentTimeMillis());
  24. System.out.println("返回值A:" + futureA.get());
  25. System.out.println("返回值B:" + futureB.get());
  26. System.out.println(" Y=" + System.currentTimeMillis());
  27. } catch (InterruptedException e) {
  28. e.printStackTrace();
  29. } catch (ExecutionException e) {
  30. e.printStackTrace();
  31. }
  32. }
  33. }

(单任务调度)从X到Y的运行时间为7秒,阻塞点是get()方法。public<V> ScheduledFuture<V> schedule(Callable<V> callable,long delay,TimeUnit unit)方法invokeAll中的第2个参数在多个任务中同时消耗时间,并不是一个任务执行完毕后再等待4秒继续执行的效果。由于第1个任务从计划任务到运行结束需要用时7秒,那么第2个任务其实是想在第4秒被执行,由于是单任务的计划任务池,所以第2个任务的执行时间被延后3秒。即使是newScheduledThreadPool(poolSize)的写法创建出来的任务池也是单任务的。

3.ScheduledThreadPoolExecutor使用Runnable延迟运行

使用Runnable接口进行无返回值的计划任务实例

  1. package mycallable;
  2. public class MyRunnableA implements Runnable {
  3. @Override
  4. public void run() {
  5. try {
  6. System.out
  7. .println("runnableA begin " + Thread.currentThread().getName() + " " + System.currentTimeMillis());
  8. Thread.sleep(3000);
  9. System.out
  10. .println("runnableA end " + Thread.currentThread().getName() + " " + System.currentTimeMillis());
  11. } catch (Exception e) {
  12. e.printStackTrace();
  13. }
  14. }
  15. }
  1. package mycallable;
  2. public class MyRunnableB implements Runnable {
  3. @Override
  4. public void run() {
  5. System.out.println("runnableB begin " + Thread.currentThread().getName() + " " + System.currentTimeMillis());
  6. System.out.println("runnableB end " + Thread.currentThread().getName() + " " + System.currentTimeMillis());
  7. }
  8. }
  1. package test.run;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import java.util.concurrent.Executors;
  5. import java.util.concurrent.ScheduledExecutorService;
  6. import java.util.concurrent.TimeUnit;
  7. import mycallable.MyRunnableA;
  8. import mycallable.MyRunnableB;
  9. public class Run {
  10. public static void main(String[] args) {
  11. List<Runnable> runnableList = new ArrayList();
  12. runnableList.add(new MyRunnableA());
  13. runnableList.add(new MyRunnableB());
  14. ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
  15. System.out.println(" X=" + System.currentTimeMillis());
  16. executor.schedule(runnableList.get(0), 0L, TimeUnit.SECONDS);
  17. executor.schedule(runnableList.get(1), 0L, TimeUnit.SECONDS);
  18. System.out.println(" Y=" + System.currentTimeMillis());
  19. }
  20. }

4.延迟运行并取得返回值

  1. package mycallable;
  2. import java.util.concurrent.Callable;
  3. public class MyCallableA implements Callable<String> {
  4. public String call() throws Exception {
  5. System.out.println("a call run =" + System.currentTimeMillis());
  6. return "returnA";
  7. }
  8. }
  1. package test.run;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import java.util.concurrent.Callable;
  5. import java.util.concurrent.ExecutionException;
  6. import java.util.concurrent.Executors;
  7. import java.util.concurrent.ScheduledExecutorService;
  8. import java.util.concurrent.ScheduledFuture;
  9. import java.util.concurrent.TimeUnit;
  10. import mycallable.MyCallableA;
  11. public class Run {
  12. public static void main(String[] args) {
  13. try {
  14. List<Callable> callableList = new ArrayList();
  15. callableList.add(new MyCallableA());
  16. ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
  17. System.out.println("X=" + System.currentTimeMillis());
  18. ScheduledFuture<String> futureA = executor.schedule(callableList.get(0), 4L, TimeUnit.SECONDS);
  19. System.out.println(futureA.get() + " A=" + System.currentTimeMillis());
  20. } catch (InterruptedException e) {
  21. e.printStackTrace();
  22. } catch (ExecutionException e) {
  23. e.printStackTrace();
  24. }
  25. }
  26. }

5.使用scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit)方法实现周期性执行(该方法有任务超时的效果)

5.1 接口scheduleAtFixedRate原型定义及参数说明

command:执行线程

initialDelay:初始化延时

period:两次开始执行最小间隔时间

unit:计时单位

  1. package mycallable;
  2. public class MyRunnable implements Runnable {
  3. @Override
  4. public void run() {
  5. try {
  6. System.out.println(
  7. " begin =" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName());
  8. Thread.sleep(4000);
  9. System.out.println(
  10. " end =" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName());
  11. } catch (InterruptedException e) {
  12. e.printStackTrace();
  13. }
  14. }
  15. }
  1. package test.run;
  2. import java.util.concurrent.Executors;
  3. import java.util.concurrent.ScheduledExecutorService;
  4. import java.util.concurrent.TimeUnit;
  5. import mycallable.MyRunnable;
  6. public class Run {
  7. public static void main(String[] args) {
  8. ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
  9. System.out.println(" X=" + System.currentTimeMillis());
  10. executor.scheduleAtFixedRate(new MyRunnable(), 1, 2, TimeUnit.SECONDS);
  11. System.out.println(" Y=" + System.currentTimeMillis());
  12. }
  13. }

scheduleAtFixedRate()方法返回的ScheduledFuture对象无法获得返回值,也就是scheduleAtFixedRate()方法不具有获得返回值的功能,而schedule()方法却可以获得返回值。所以当使用scheduleAtFixedRate()方法实现重复运行任务的效果时,需要结合自定义的Runnable接口的实现类,不要使用FutureTask类,因为FutureTask类并不能实现重复运行的效果。

6.使用scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit)方法实现周期性执行(该方法没有超时与非超时的情况)

command:执行线程

initialDelay:初始化延时

period:前一次执行结束到下一次执行开始的间隔时间(间隔执行延迟时间)

unit:计时单位

  1. package mycallable;
  2. public class MyRunnable implements Runnable {
  3. @Override
  4. public void run() {
  5. try {
  6. System.out.println(
  7. " begin =" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName());
  8. Thread.sleep(4000);
  9. System.out.println(
  10. " end =" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName());
  11. } catch (InterruptedException e) {
  12. e.printStackTrace();
  13. }
  14. }
  15. }
  1. package test.run;
  2. import java.util.concurrent.Executors;
  3. import java.util.concurrent.ScheduledExecutorService;
  4. import java.util.concurrent.TimeUnit;
  5. import mycallable.MyRunnable;
  6. public class Run {
  7. public static void main(String[] args) {
  8. ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
  9. System.out.println(" X=" + System.currentTimeMillis());
  10. executor.scheduleWithFixedDelay(new MyRunnable(), 1, 2, TimeUnit.SECONDS);
  11. System.out.println(" Y=" + System.currentTimeMillis());
  12. }
  13. }

7.使用getQueue()与remove()方法

方法getQueue()的作用是取得队列中的任务,而这些任务是未来将要运行的,正在运行的任务不在此队列中。使用scheduleAtFixedRate()和scheduleWithFixedDelay()两个方法实现周期性执行任务时,未来欲执行的任务都是放入此队列中。

  1. package mycallable;
  2. public class MyRunnable implements Runnable {
  3. private String username;
  4. public MyRunnable(String username) {
  5. super();
  6. this.username = username;
  7. }
  8. public String getUsername() {
  9. return username;
  10. }
  11. public void setUsername(String username) {
  12. this.username = username;
  13. }
  14. @Override
  15. public void run() {
  16. System.out.println("run! username=" + username + " " + Thread.currentThread().getName());
  17. }
  18. }
  1. package test.run;
  2. import java.util.Iterator;
  3. import java.util.concurrent.BlockingQueue;
  4. import java.util.concurrent.ScheduledThreadPoolExecutor;
  5. import java.util.concurrent.TimeUnit;
  6. import mycallable.MyRunnable;
  7. public class Run1 {
  8. public static void main(String[] args) {
  9. ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(10);
  10. Runnable runnable1 = new MyRunnable("A");
  11. Runnable runnable2 = new MyRunnable("B");
  12. Runnable runnable3 = new MyRunnable("C");
  13. Runnable runnable4 = new MyRunnable("D");
  14. Runnable runnable5 = new MyRunnable("E");
  15. System.out.println(runnable1.hashCode());
  16. System.out.println(runnable2.hashCode());
  17. System.out.println(runnable3.hashCode());
  18. System.out.println(runnable4.hashCode());
  19. System.out.println(runnable5.hashCode());
  20. executor.scheduleAtFixedRate(runnable1, 10, 2, TimeUnit.SECONDS);
  21. executor.scheduleAtFixedRate(runnable2, 10, 2, TimeUnit.SECONDS);
  22. executor.scheduleAtFixedRate(runnable3, 10, 2, TimeUnit.SECONDS);
  23. executor.scheduleAtFixedRate(runnable4, 10, 2, TimeUnit.SECONDS);
  24. executor.scheduleAtFixedRate(runnable5, 10, 2, TimeUnit.SECONDS);
  25. System.out.println("");
  26. BlockingQueue<Runnable> queue = executor.getQueue();
  27. Iterator<Runnable> iterator = queue.iterator();
  28. while (iterator.hasNext()) {
  29. Runnable runnable = (Runnable) iterator.next();
  30. System.out.println("队列中的:" + runnable);
  31. }
  32. }
  33. }
  1. package test.run;
  2. import java.util.Iterator;
  3. import java.util.concurrent.BlockingQueue;
  4. import java.util.concurrent.ScheduledFuture;
  5. import java.util.concurrent.ScheduledThreadPoolExecutor;
  6. import java.util.concurrent.TimeUnit;
  7. import mycallable.MyRunnable;
  8. public class Run2 {
  9. public static void main(String[] args) throws InterruptedException {
  10. ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
  11. Runnable runnable1 = new MyRunnable("A");
  12. Runnable runnable2 = new MyRunnable("B");
  13. ScheduledFuture future1 = executor.scheduleAtFixedRate(runnable1, 0, 2, TimeUnit.SECONDS);
  14. Thread.sleep(1000);
  15. ScheduledFuture future2 = executor.scheduleAtFixedRate(runnable2, 10, 2, TimeUnit.SECONDS);
  16. Thread.sleep(5000);
  17. System.out.println(executor.remove((Runnable) future2));
  18. System.out.println("");
  19. BlockingQueue<Runnable> queue = executor.getQueue();
  20. Iterator<Runnable> iterator = queue.iterator();
  21. while (iterator.hasNext()) {
  22. Runnable runnable = (Runnable) iterator.next();
  23. System.out.println("队列中的:" + runnable);
  24. }
  25. }
  26. }

8.方法setExecuteExistingDelayedTasksAfterShutdownPolicy()的使用

方法setExecuteExistingDelayedTasksAfterShutdownPolicy()的作用是当对ScheduledThreadPoolExecutor执行了shutdown()方法时,任务是否继续执行,默认值是true,也就是当调用了shutdown()方法时任务还是继续运行,当使用setExecuteExistingDelayedTasksAfterShutdownPolicy(false)时任务不再运行。

  1. package mycallable;
  2. public class MyRunnable implements Runnable {
  3. private String username;
  4. public MyRunnable(String username) {
  5. super();
  6. this.username = username;
  7. }
  8. public String getUsername() {
  9. return username;
  10. }
  11. public void setUsername(String username) {
  12. this.username = username;
  13. }
  14. @Override
  15. public void run() {
  16. System.out.println("run! username=" + username + " " + Thread.currentThread().getName() + " "
  17. + System.currentTimeMillis());
  18. }
  19. }
  1. package test.run;
  2. import java.util.concurrent.ScheduledThreadPoolExecutor;
  3. import java.util.concurrent.TimeUnit;
  4. import mycallable.MyRunnable;
  5. /**
  6. * 虽然shutdown()但任务还是执行了
  7. * @author linhaiy
  8. *
  9. */
  10. public class Run1 {
  11. public static void main(String[] args) throws InterruptedException {
  12. ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
  13. Runnable runnable1 = new MyRunnable("A");
  14. Runnable runnable2 = new MyRunnable("B");
  15. executor.schedule(runnable1, 3, TimeUnit.SECONDS);
  16. executor.shutdown();
  17. System.out.println("已经shutdown了");
  18. }
  19. }
  1. package test.run;
  2. import java.util.concurrent.ScheduledThreadPoolExecutor;
  3. import java.util.concurrent.TimeUnit;
  4. import mycallable.MyRunnable;
  5. /**
  6. * 任务被取消执行,进程销毁了
  7. * @author linhaiy
  8. *
  9. */
  10. public class Run2 {
  11. public static void main(String[] args) {
  12. ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
  13. Runnable runnable1 = new MyRunnable("A");
  14. Runnable runnable2 = new MyRunnable("B");
  15. executor.schedule(runnable1, 3, TimeUnit.SECONDS);
  16. executor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
  17. executor.shutdown();
  18. System.out.println("已经shutdown了");
  19. }
  20. }

方法setExecuteExistingDelayedTasksAfterShutdownPolicy()可以与schedule()和shutdown()方法联合使用,但setExecuteExistingDelayedTasksAfterShutdownPolicy()方法不能与scheduleAtFixedRate()和scheduleWithFixedDelay()方法联合使用。那么如果想实现shutdown关闭线程池后,池中的任务还会继续重复运行, 则要将scheduleAtFixedRate()和scheduleWithFixedDelay()方法与setExecuteExistingDelayedTasksAfterShutdownPolicy()方法联合使用。

9.方法setContinueExistingPeriodicTasksAfterShutdownPolicy()

方法setContinueExistingPeriodicTasksAfterShutdownPolicy()传入true的作用是当使用scheduleAtFixedRate()方法或scheduleWithFixedDelay()方法时,如果调用ScheduledThreadPoolExecutor对象的shutdown()方法,任务还会继续运行,传入false时任务不运行,进程销毁。如果使用scheduleAtFixedRate()结合shutdown()方法想实现任务继续运行的效果,则必须使用setContinueExistingPeriodicTasksAfterShutdownPolicy(true)代码。

  1. package mycallable;
  2. public class MyRunnable implements Runnable {
  3. private String username;
  4. public MyRunnable(String username) {
  5. super();
  6. this.username = username;
  7. }
  8. public String getUsername() {
  9. return username;
  10. }
  11. public void setUsername(String username) {
  12. this.username = username;
  13. }
  14. @Override
  15. public void run() {
  16. System.out.println("run! username=" + username + " " + Thread.currentThread().getName() + " "
  17. + System.currentTimeMillis());
  18. }
  19. }
  1. package test.run;
  2. import java.util.concurrent.ScheduledThreadPoolExecutor;
  3. import java.util.concurrent.TimeUnit;
  4. import mycallable.MyRunnable;
  5. public class Run1 {
  6. public static void main(String[] args) {
  7. ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(10);
  8. Runnable runnable1 = new MyRunnable("A");
  9. executor.scheduleAtFixedRate(runnable1, 1, 2, TimeUnit.SECONDS);
  10. executor.shutdown();
  11. System.out.println("执行了shutdown!");
  12. }
  13. }
  1. package test.run;
  2. import java.util.concurrent.ScheduledThreadPoolExecutor;
  3. import java.util.concurrent.TimeUnit;
  4. import mycallable.MyRunnable;
  5. public class Run2 {
  6. public static void main(String[] args) {
  7. ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(10);
  8. Runnable runnable1 = new MyRunnable("A");
  9. executor.scheduleAtFixedRate(runnable1, 1, 2, TimeUnit.SECONDS);
  10. executor.setContinueExistingPeriodicTasksAfterShutdownPolicy(true);
  11. executor.shutdown();
  12. System.out.println("执行了shutdown!");
  13. }
  14. }

10.使用cancel(boolean)与setRemoveOnCancelPolicy()方法

10.1 方法cancel(boolean)的作用设定是否取消任务。

10.2 方法setRemoveOnCancelPolicy(boolean)的作用设定是否将取消后的任务从队列中清除。

10.3 当执行cancel()方法后任务虽然被成功取消,但还是在队列中存在。

10.4 在队列中的任务被成功取消,任务也不再运行。

10.5 正在运行的任务可以停止,但要结合if(Thread.currentThread().isInterrupted() == true)判断。

10.6 使用setRemoveOnCancelPolicy(true)代码结合cancel(true),则队列中的任务被删除

总结:在此介绍了基于线程池ThreadPoolExecutor的ScheduledThreadPoolExecutor计划任务执行池对象,使用此类可以高效地实现计划任务线程池,不再重复创建Thread对象,提高了运行效率。此类也支持间隔运行的功能。

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
  

闽ICP备14008679号