博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ThreadPoolExecutor分析
阅读量:5206 次
发布时间:2019-06-14

本文共 2940 字,大约阅读时间需要 9 分钟。

摘至:

http://blog.csdn.net/cutesource/article/details/6061229

http://songzi0206.iteye.com/blog/1211546

 

 

既然最终任务都是由execute(Runnable)方法执行,就直接来看该方法实现的所在类。

首当其冲肯定是类ThreadPoolExecutor了,相信他是java concurrent包中用的最多的一个

线程池执行器,包括spring中ThreadPoolTaskExecutor也是利用它来执行任务的。从类的

“家谱”来看,ThreadPoolExecutor直接继承自AbstractExecutorService,因此必须实现的方

法只有public void execute(Runnable command),查看之发现和想象不一样(原以为他会直接

以此runnable创建一个thread然后直接start, ^_^),他内部还会其他的执行逻辑,那是因

为ThreadPoolExecutor内部会维护一个线程池,所以有很多额外的操作。所以接下来需要

先来分析一下该类。

         首先定义了线程执行的四种状态,便于跟踪:

 

Java代码  
  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;   

 

 

 

 

         其次,定义了三个表示大小的int类型

 

Java代码  
  1. //核心线程池大小   
  2. private volatile int corePoolSize;   
  3. //线程池允许的最大线程数量   
  4. private volatile int maximumPoolSize;   
  5. //当前线程池中的线程数量   
  6. private volatile int poolSize;   

 

 

 

 

 

再仔细看,发现ThreadPoolExecutor主要依赖于以下类或接口:

1)      BlockingQueue<Runnable>

用于传输和保持提交的任务,可以使用此队列与池大小进行交互:

Ø  如果运行的线程少于 corePoolSize,则 Executor 始终首选添加新的线程,而不进行排队。

Ø  如果运行的线程等于或多于 corePoolSize,则 Executor 始终首选将请求加入队列,而不添加新的线程。

Ø  如果无法将请求加入队列,则创建新的线程,除非创建此线程超出 maximumPoolSize,在这种情况下,任务将被拒绝

     任务排队等待执行,排队的策略根据不同的BlockingQueue实现类型不同,具体 

  分SynchronousQueue(直接提交策略,这是默认值),LinkedBlockingQueue(无界队列),

ArrayBlockingQueue(有界队列)等。

 

2)      RejectedExecutionHandler

用来拒绝一个任务的执行,有两种情况会发生这种情况。一是在execute方法中若

addIfUnderMaximumPoolSize(command)为false,即线程池已经饱和;二也是在execute方法中, 发现runState!=RUNNING || poolSize == 0,即已经shutdown,就调用ensureQueuedTaskHandled(Runnable command),在该方法中有可能调用reject。Reject策略预定义有四种:

Ø  在默认的 ThreadPoolExecutor.AbortPolicy 中,处理程序遭到拒绝将抛出运行时RejectedExecutionException。

Ø  在 ThreadPoolExecutor.CallerRunsPolicy 中,线程调用运行该任务的 execute 本身。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度

Ø  在 ThreadPoolExecutor.DiscardPolicy 中,不能执行的任务将被删除

Ø  在 ThreadPoolExecutor.DiscardOldestPolicy 中,如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序(如果再次失败,则重复此过程)

 

1)      ThreadFactory

         默认使用Executors.DefaultThreadFactory,主要用来创建线程,统一设置线程的一些属性(名字、分组、优先级、是否后台线程等)。也可以使用自定义ThreadFactory,若有需要的话,比如想设置线程的UncaughtExceptionHandler等。

 

2)      ThreadPoolExecutor.Worker

            ThreadPoolExecutor是把线程包装成Worker对象运行的,这里要弄清一个概念,ThreadPoolExecutor用来执行线程Thread, 而线程Thread执行会去运行任务Runnable,所以ThreadPoolExecutor也可以说成任务执行器。还记得上一篇讲到submit,invokeAll等方法会将Runnable任务包装成FutureTask运行的。

            包装也可以理解成代理,一旦有了代理对象,就可以在运行目标对象的时候做很多有意义的事情,Spring很多强悍的功能都是基于代理实现,有点说远了,但是以后的分析中将会体会到这个包装确实起到很大的作用。

 

3)      TimeUnit

 

这个枚举是java  concurrent提供的工具,主要提供时间不同粒度单元之间的转换和执行计时以及延迟操作等。

 

4)      ReentrantLock

         关于java.util.concurrent.lock包以后会详细写,这里简单介绍下。这是一个可重入的互斥锁,实现了synchronized隐式监视器锁差不多的功能,但是粒度更细,功能更强。Synchronized在语义的层次实现,它是不能被中断的;而Lock是在java语法层面实现,它可以被中断。这个很重要,Java concrruent不鼓励直接使用Thread.interrupt等方法来中断,而尽量使用Executor来执行所有的操作。Executor在shutdown或者在提交任务后返回的future中执行cancel的话,底层会调用interrupt来结束线程。ThreadPoolExecutor需要对线程执行进行跟踪管理,同步自然要用灵活且可以中断的Lock,而不可能去使用synchronized。

5)      Condition

     Lock替代了synchronized,condition用来替代Object的监视器方法(wait,notifyAll, notify)。 

        

        到此,基本上算是弄清了ThreadPoolExecutor的结构,具体的功能分析看来得放到下一篇了,基本类图可以参考如下: 

转载于:https://www.cnblogs.com/KeyChan/p/3534907.html

你可能感兴趣的文章
Java -- Swing 组件使用
查看>>
Software--Architecture--DesignPattern IoC, Factory Method, Source Locator
查看>>
poj1936---subsequence(判断子串)
查看>>
黑马程序员_Java基础枚举类型
查看>>
【redis4 】
查看>>
shell文件查找和压缩命令
查看>>
python学习笔记7(使用字符串)
查看>>
[ python ] 练习作业 - 2
查看>>
内省、JavaBean、PropertyDescriptor类、Introspector类、BeanUtils工具包、注解、Rentention、Target、注解的基本属性和高级属性...
查看>>
iOS 地图(MKMapView)
查看>>
一位90后程序员的自述:如何从年薪3w到30w!
查看>>
HDU-1242-Rescue
查看>>
在.net core上使用Entity FramWork(Db first)
查看>>
linux命令总结sed命令详解
查看>>
obiee11g中关闭缓存
查看>>
Eclipse中如何开启断言(Assert),方法有二
查看>>
System.Net.WebException: 无法显示错误消息,原因是无法找到包含此错误消息的可选资源程序集...
查看>>
Eclipse注释模板
查看>>
WordCount运行详解
查看>>
压缩图片 待验证
查看>>