[转载] Java多线程之Executor框架

 

Executor框架

Executor是一套线程池管理框架。是JDK 1.5中引入的一系列并发库中与Executor相关的功能类,其中最核心的类就是常见的ThreadPoolExecutor。

1、Executor框架组成部分

😐 工作任务:就是Runnable/Callable接口的实现,可以被线程池执行;

😐 异步计算结果:Future接口。实现Future接口的FutureTask类,代表异步处理结果;

😐 执行机制:

  • Executor接口:只有一个execute()方法;

  • ExecutorService接口: ExecutorService扩展了Executor接口,增加了生命周期的管理方法。
    ExecutorService的生命周期包括三种状态:运行、关闭、终止
    创建后便进入运行状态,当调用了shutdown()方法时,便进入关闭状态,此时意味着ExecutorService不再接受新的任务,但它还在执行已经提交了submit()的任务,当已经提交了的任务执行完后,便到达终止状态。

  • ScheduledExecutorService接口:任务调度的线程池实现,可以在给定的延迟后运行命令或者定期执行命令;

  • ThreadPoolExecutor:最核心的线程池实现,用来执行被提交的任务;

 

2、ThreadPoolExecutor核心参数

Executor是线程池的顶级接口,接口中只定义了一个方法 void execute(Runnable command);线程池的操作方法都是定义子在ExecutorService子接口中的,所以说ExecutorService是线程池真正的接口。

ThreadPoolExecutor提供了四个构造方法,来看下重要参数:

public ThreadPoolExecutor(

int corePoolSize,

int maximumPoolSize,

long keepAliveTime,

TimeUnit unit,

BlockingQueue<Runnable> workQueue,

ThreadFactory threadFactory,

RejectedExecutionHandler handler) {}

 

参数含义如下:

  • corePoolSize: 线程池核心线程数

  • maximumPoolSize:线程池最大数

  • keepAliveTime: 空闲线程存活时间

  • unit: 时间单位

  • workQueue: 线程池所使用的缓冲队列

  • threadFactory:线程池创建线程使用的工厂

  • handler: 线程池对拒绝任务的处理策略

默认的线程工厂,创建的线程是普通的非守护线程,如果需要定制,实现ThreadFactory后传给ThreadPoolExecutor即可。

3、线程池的生命周期

线程池的生命周期,总共有五种状态:

  • RUNNING(111) :能接受新提交的任务,并且也能处理阻塞队列中的任务;

  • SHUTDOWN(000):关闭状态,不再接受新提交的任务,但却可以继续处理阻塞队列中已保存的任务。在线程池处于 RUNNING 状态时,调用 shutdown()方法会使线程池进入到该状态。(finalize() 方法在执行过程中也会调用shutdown()方法进入该状态);

  • STOP(001):不能接受新任务,也不处理队列中的任务,会中断正在处理任务的线程。在线程池处于 RUNNING 或 SHUTDOWN 状态时,调用 shutdownNow() 方法会使线程池进入到该状态;

  • TIDYING(010):如果所有的任务都已终止了,workerCount (有效线程数) 为0,线程池进入该状态后会调用 terminated() 方法进入TERMINATED 状态。

  • TERMINATED(011):在terminated() 方法执行完后进入该状态,默认terminated()方法中什么也没有做。

ThreadPoolExecutor 使用int的高三位表示线程池状态,低29位表示线程数量;

 

4、四种线程池的创建方式

Executors类提供了一系列工厂方法用于创建线程池:

  • public static ExecutorService newFixedThreadPool(int nThreads)
    创建固定数目线程的线程池

  • public static ExecutorService newCachedThreadPool()
    创建一个可缓存的线程池,调用execute将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线 程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。

  • public static ExecutorService newSingleThreadExecutor()
    创建一个单线程化的Executor

  • public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
    创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代Timer类。

5、线程池实现原理(重点!!!)

  • 如果运行线程数小于corePoolSize,那么马上创建线程运行这个任务;

  • 如果正在运行的线程数大于等于corePoolSize,那么将这个任务放进队列;

  • 如果队列放满了,如果正在运行的线程数小于maximumPoolSize,创建线程处理任务;

  • 如果队列放满了,正在运行的线程数大于等于maximumPoolSize,那么线程会抛出异常;RejectExecutionException,执行拒绝策略。

6、线程池4种拒绝策略

  • AbortPolicy :直接抛出异常,阻止系统运行(线程池默认的拒绝策略);

  • CallerRunsPolicy:由调用线程处理;

  • DiscardPolicy:丢弃无法处理的任务,不予任何处理;

  • DiscardOldestPolicy:丢弃最老的一个请求,也就是即将被执行的一个任务,重新提交被拒绝的任务。

小结:Java线程池中两种提交任务的方法submit() 和 execute()有什么区别?

两个方法都可以向线程池提交任务,execute()方法的返回类型是void,它定义在Executor接口中。而submit()方法可以返回持有计算结果的Future对象,它定义在ExecutorService接口中,它扩展了Executor接口,其它线程池类像ThreadPoolExecutor和ScheduledThreadPoolExecutor都有这些方法。

#Java#
posted @ 2024-04-24 10:45  YukiRinLL  阅读(2)  评论(0编辑  收藏  举报