[关闭]
@adamhand 2018-12-23T22:05:04.000000Z 字数 5366 阅读 1127

Java并发-Executor框架和线程池


Executor框架



Executor接口

  1. public interface Executor {
  2. void execute(Runnable command);
  3. }

Executor接口是Executor框架中最基础的部分,定义了一个用于执行Runnable的execute方法,它没有实现类只有另一个重要的子接口ExecutorService

ExecutorService接口

  1. //继承自Executor接口
  2. public interface ExecutorService extends Executor {
  3. /**
  4. * 关闭方法,调用后执行之前提交的任务,不再接受新的任务
  5. */
  6. void shutdown();
  7. /**
  8. * 从语义上可以看出是立即停止的意思,将暂停所有等待处理的任务并返回这些任务的列表
  9. */
  10. List<Runnable> shutdownNow();
  11. /**
  12. * 判断执行器是否已经关闭
  13. */
  14. boolean isShutdown();
  15. /**
  16. * 关闭后所有任务是否都已完成
  17. */
  18. boolean isTerminated();
  19. /**
  20. * 中断
  21. */
  22. boolean awaitTermination(long timeout, TimeUnit unit)
  23. throws InterruptedException;
  24. /**
  25. * 提交一个Callable任务
  26. */
  27. <T> Future<T> submit(Callable<T> task);
  28. /**
  29. * 提交一个Runable任务,result要返回的结果
  30. */
  31. <T> Future<T> submit(Runnable task, T result);
  32. /**
  33. * 提交一个任务
  34. */
  35. Future<?> submit(Runnable task);
  36. /**
  37. * 执行所有给定的任务,当所有任务完成,返回保持任务状态和结果的Future列表
  38. */
  39. <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
  40. throws InterruptedException;
  41. /**
  42. * 执行给定的任务,当所有任务完成或超时期满时(无论哪个首先发生),返回保持任务状态和结果的 Future 列表。
  43. */
  44. <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
  45. long timeout, TimeUnit unit)
  46. throws InterruptedException;
  47. /**
  48. * 执行给定的任务,如果某个任务已成功完成(也就是未抛出异常),则返回其结果。
  49. */
  50. <T> T invokeAny(Collection<? extends Callable<T>> tasks)
  51. throws InterruptedException, ExecutionException;
  52. /**
  53. * 执行给定的任务,如果在给定的超时期满前某个任务已成功完成(也就是未抛出异常),则返回其结果。
  54. */
  55. <T> T invokeAny(Collection<? extends Callable<T>> tasks,
  56. long timeout, TimeUnit unit)
  57. throws InterruptedException, ExecutionException, TimeoutException;
  58. }

ExecutorService接口继承自Executor接口,定义了终止、提交、执行任务、跟踪任务返回结果等方法。

ExecutorService的生命周期有三种状态:运行关闭已终止

工具类Executors的静态方法

负责生成各种类型的ExecutorService线程池实例,共有四种。

Runnable、Callable、Future接口

Runnable接口

  1. // 实现Runnable接口的类将被Thread执行,表示一个基本的任务
  2. public interface Runnable {
  3. // run方法就是它所有的内容,就是实际执行的任务
  4. public abstract void run();
  5. }

Callable接口

与Runnable接口的区别在于它接收泛型,同时它执行任务后带有返回内容

  1. // Callable同样是任务,与Runnable接口的区别在于它接收泛型,同时它执行任务后带有返回内容
  2. public interface Callable<V> {
  3. // 相对于run方法的带有返回值的call方法
  4. V call() throws Exception;
  5. }

Runnable接口和Callable接口的实现类,都可以被ThreadPoolExecutor和ScheduledThreadPoolExecutor执行,他们之间的区别是Runnable不会返回结果,而Callable可以返回结果。

Executors可以把一个Runnable对象转换成Callable对象:

  1. public static Callable<Object> callable(Runnbale task);

当把一个Callable对象(Callable1,Callable2)提交给ThreadPoolExecutor和ScheduledThreadPoolExecutor执行时,submit(...)会向我们返回一个FutureTask对象。我们执行FutureTask.get()来等待任务执行完成,当任务完成后,FutureTask.get()将返回任务的结果。

Future接口

  1. // Future代表异步任务的执行结果
  2. public interface Future<V> {
  3. /**
  4. * 尝试取消一个任务,如果这个任务不能被取消(通常是因为已经执行完了),返回false,否则返回true。
  5. */
  6. boolean cancel(boolean mayInterruptIfRunning);
  7. /**
  8. * 返回代表的任务是否在完成之前被取消了
  9. */
  10. boolean isCancelled();
  11. /**
  12. * 如果任务已经完成,返回true
  13. */
  14. boolean isDone();
  15. /**
  16. * 获取异步任务的执行结果(如果任务没执行完将等待)
  17. */
  18. V get() throws InterruptedException, ExecutionException;
  19. /**
  20. * 获取异步任务的执行结果(有最常等待时间的限制)
  21. *
  22. * timeout表示等待的时间,unit是它时间单位
  23. */
  24. V get(long timeout, TimeUnit unit)
  25. throws InterruptedException, ExecutionException, TimeoutException;
  26. }

Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果。必要时可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果

也就是说Future提供了三种功能:

线程池的处理流程



线程池优先要创建出基本线程池大小(corePoolSize)的线程数量,没有达到这个数量时,每次提交新任务都会直接创建一个新线程,当达到了基本线程数量后,又有新任务到达,优先放入等待队列,如果队列满了,才去创建新的线程(不能超过线程池的最大数maxmumPoolSize)。

向线程池提交任务的两种方式

通过execute()方法

  1. ExecutorService threadpool= Executors.newFixedThreadPool(10);
  2. threadpool.execute(new Runnable(){...});

这种方式提交没有返回值,也就不能判断任务是否被线程池执行成功。

通过submit()方法

  1. Future<?> future = threadpool.submit(new Runnable(){...});
  2. try {
  3. Object res = future.get();//获取任务执行结果
  4. } catch (InterruptedException e) {
  5. // 处理中断异常
  6. e.printStackTrace();
  7. } catch (ExecutionException e) {
  8. // 处理无法执行任务异常
  9. e.printStackTrace();
  10. }finally{
  11. // 关闭线程池
  12. executor.shutdown();
  13. }

使用submit 方法来提交任务,它会返回一个Future对象,通过future的get方法来获取返回值,get方法会阻塞住直到任务完成,而使用get(long timeout, TimeUnit unit)方法则会阻塞一段时间后立即返回,这时有可能任务没有执行完。

线程池本身的状态

  1. volatile int runState;
  2. static final int RUNNING = 0; //运行状态
  3. static final int SHUTDOWN = 1; //关闭状态
  4. static final int STOP = 2; //停止
  5. static final int TERMINATED = 3; //终止,终结

ForkJoinPool

ForkJoinPool是jdk1.7新引入的线程池,基于ForkJoin框架,使用了“分治”的思想。关于ForkJoin框架参考另一篇笔记“Java并发之J.U.C”。

ThreadPoolExecutor中每个任务都是由单个线程独立处理的,如果出现一个非常耗时的大任务(比如大数组排序),就可能出现线程池中只有一个线程在处理这个大任务,而其他线程却空闲着,这会导致CPU负载不均衡:空闲的处理器无法帮助工作繁忙的处理器。

ForkJoinPool就是用来解决这种问题的:将一个大任务拆分成多个小任务后,使用fork可以将小任务分发给其他线程同时处理,使用join可以将多个线程处理的结果进行汇总;这实际上就是分治思想的并行版本

ForkJoinPool基本原理

ForkJoinPool 类是Fork/Join 框架的核心,和ThreadPoolExecutor一样它也是ExecutorService接口的实现类。

所以上面的线程池框架图是比较老的了,新的框架图如下图所示:



(未完待续)
https://www.jianshu.com/p/32a15ef2f1bf
https://www.jianshu.com/p/de025df55363
https://blog.csdn.net/Holmofy/article/details/82714665
https://www.cnblogs.com/lixuwu/p/7979480.html

参考

Java的Executor框架和线程池实现原理
Java并发编程:线程池的使用

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注