ThreadPoolExecutor的用法

Java中的线程池

  • 一般我们说起Java中的线程池,其实指的是java.util.concurrent包下的ThreadPoolExecutor。当然java包下还有其他线程池的实现类,但主要也是最常用的就是这个类。今天我们来好好说说这个类。
  • 这里我们结合了其他人的整理和自己的思考进行了总结。

1. 工作原理

如图所示:


ThreadPoolExecutor工作原理

当主线程中调用execute接口提交执行任务时:
则执行以下步骤:
注意:线程池初始时,是空的。

  1. 如果当前线程数<corePoolSize,如果是则创建新的线程执行该任务
  2. 如果当前线程数>=corePoolSize,则将任务存入BlockingQueue<Runnable>
  3. 如果阻塞队列已满,且当前线程数<maximumPoolSize,则新建线程执行该任务。
  4. 如果阻塞队列已满,且当前线程数>=maximumPoolSize,则抛出异常RejectedExecutionException,告诉调用者无法再接受任务了。
注意点:
  • 线程池初始化时,是空的。
  • 如果阻塞队列已满,且当前线程数<maximumPoolSize,则新建线程执行该任务。而不是新建线程,从阻塞队列里take任务来执行,所以这里并不是先来先执行的。
提问:这里的阻塞队列是BlockingQueue<Runnale>,我们知道ThreadPoolExecutor是支持Callable任务提交的,那这里不会有问题吗?
  • 答:其实我们这里说的都是execute接口提交任务。execute接口只接受Runnable。其实我们看一下继承关系图:


    ThreadPoolExecutor类图
  • 可以看到其实ThreadPoolExecutor是继承了AbstractExecutorService,而AbstractExecutorService实现了ExecutorService。

  • 且我们可以看到ThreadPoolExecutor类里只重写了execute方法。ExecutorService的其他方法都没有实现,而是在AbstractExecutorService里实现的。所以说整个ThreadPoolExecutor里的策略都是只针对execute方法来说的。所以说上述的工作原理只针对execute接口。像其他的submit/invoke接口并不适用--因为调用这些接口其实调用的是AbstractExecutorService的实现。

2. 我们来看一下ThreadPoolExecutor的参数

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)
  • corePoolSize:就是上图中的CorePoolSize,意为核心线程数。
  • maximumPoolSize:就是上图中maximumPoolSize,意为整个线程池的最大线程数。这个数字是包含orePoolSize的。
  • keepAliveTime和unit:是idle线程最大存活时间。unit是前者的单位。即如果当前线程数>corePoolSize,则会kill一些线程至corePoolSize大小。
  • workQueue:就是上面说的阻塞队列,注意BlockingQueue<Runnable>只是个接口,下面我们会细说一下它的常用实现类。
  • 下面两个参数是可选项:即Java重载了ThreadPoolExecutor的构造方法,下面两个参数可以不传,也可以只传一个。
  • threadFactory:线程工厂。创建线程的接口,该接口只有一个方法:Thread newThread(Runnable r);我们可以实现这个接口进而自定义创建线程,比如制定线程名称,线程组等。
  • handler:当线程池已满时,再提交任务会触发调用这个回调函数。RejectedExecutionHandler接口的唯一方法:
void rejectedExecution(Runnable r, ThreadPoolExecutor executor);

3. 阻塞队列的常用实现类

  • ArrayBlockingQueue: 有边界的阻塞队列。长度大小初始化时制定,即内部由数组实现。
  • LinkedBlockingQueue: 有边界的阻塞队列。边界是可选的,如果初始化的时候不指定则默认是Interger.MAX_VALUE,内部由链表实现。(最常用)
  • PriorityBlockQueue: 带有优先级的阻塞队列。没有边界。
  • 这三个类都实现了BlockingQueue接口,其中LinkedBlockingQueue最常用,特别注意一般一定要指定边界大小,不然线程池失去了些意义,且造成内存泄露。
    这里就不对这些细说,以后我们再细说。

4. RejectedExecutionHandler线程池饱和策略

  • 默认的 ThreadPoolExecutor.AbortPolicy:处理程序遭到拒绝将抛出运行时RejectedExecutionException。
  • ThreadPoolExecutor.CallerRunsPolicy:调用线程直接call该任务的execute 本身。
  • ThreadPoolExecutor.DiscardPolicy:将任务删除。
  • ThreadPoolExecutor.DiscardOldestPolicy删除工作队列头部任务。

5. ThreadPoolExecutor的扩展

我们看ThreadPoolExecutor的源码发现如下三个函数的实现为空且是protected。明显用于子类实现的。

protected void beforeExecute(Thread t, Runnable r) { }  
protected void afterExecute(Runnable r, Throwable t) { }  
protected void terminated() { } 
  • 在执行任务的线程中将调用beforeExecute和afterExecute等方法,在这些方法中还可以添加日志、计时、监视或者统计信息收集的功能。
  • 无论任务是从run中正常返回,还是抛出一个异常而返回,afterExecute都会被调用。如果任务在完成后带有一个Error,那么就不会调用afterExecute。
  • 如果beforeExecute抛出一个RuntimeException,那么任务将不被执行,并且afterExecute也不会被调用。
  • 在线程池完成关闭时调用terminated,也就是在所有任务都已经完成并且所有工作者线程也已经关闭后,terminated可以用来释放Executor在其生命周期里分配的各种资源,此外还可以执行发送通知、记录日志或者手机finalize统计等操作。
    即我们可以子类来继承ThreadPoolExecutor来定制化一些功能。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,186评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,858评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,620评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,888评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,009评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,149评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,204评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,956评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,385评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,698评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,863评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,544评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,185评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,899评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,141评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,684评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,750评论 2 351

推荐阅读更多精彩内容