一 简述

线程池,作为一个管理一组同构工作线程的资源。接受提交的任务,利用线程池中的线程进行工作的处理。 在另一篇《Java多线程设计模式(4)线程池模式》利用非Executors描述了线程池基本构建过程,对于线程池基本机制进行了说明。由于Java类库中有Executor来专门用于线程池的管理的类,所以可以用Executor任务执行框架来实现线程池的构建。

Executor核心的思想就是将请求处理任务的提交线程和任务的实际执行解耦开来。利用execute来传递一个具体执行的Runnable任务类,或者利用submit来传递一个Runnable任务类或Callable获取任务返回值的任务。

对于每次通过execute方法提交的任务执行顺序如下:

1、会判断当前池线程以及核心数目的大小,当池中当前的线程数小于核心线程数时,会创建新的线程。具体创建新线程流程如:获取内置锁,将任务添加到内部的BlockingQueue任务队列中,再利用工厂方法产生一个执行该任务的线程,这个线程是非守护及优先级是NORM的线程。

2、当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列。

3、当线程数大于等于核心线程数,且任务队列已满,采用以下处理方式

若线程数小于最大线程数,创建线程

若线程数等于最大线程数,抛出异常,拒绝任务,进行饱和处理策略。

Executor任务执行框架类图如下:

二 ThreadPoolExecutor线程池

一般线程池可以直接利用构造器来实例化一个ThreadPoolExecutor,也可以利用Executors工具类来创建一个线程池。也可以通过继承扩展ThreadPoolExecutor来自定义一些ThreadPoolExecutor子类。

在利用Executors静态生成ThreadPoolExecutor的时候,都会在内部实例化一个ThreadPoolExecutor。在ThreadPoolExecutor内部都是用BlockingQueue队列来保存提交的任务Runnable。

一个ThreadPoolExecutor需要考虑三个方面:

一个是线程池的大小,二个是任务队列的大小,三个是饱和策略

常见的用法就是利用Executors的静态工厂来创建。

标准的ThreadPoolExecutor构造方法如下:

1
2
3
4
5
6
7
public ThreadPoolExecutor(int corePoolSize,
        int maximumPoolSize,
        long keepAliveTime,
        TimeUnit
unit,
        BlockingQueue<Runnable>
workQueue,
        ThreadFactory
threadFactory,
        RejectedExecutionHandler
handler)

ThreadPoolExecutor的几个参数说明:

corePoolSize

核心线程数,核心线程会一直存活,即使没有任务需要处理。当线程数小于核心线程数时,即使现有的线程空闲,线程池也会优先创建新线程来处理任务,而不是直接交给现有的线程处理。

核心线程在allowCoreThreadTimeout被设置为true时会超时退出,默认情况下不会退出。

maxPoolSize

当线程数大于或等于核心线程,且任务队列已满时,线程池会创建新的线程,直到线程数量达到maxPoolSize。如果线程数已等于maxPoolSize,且任务队列已满,则已超出线程池的处理能力,线程池会拒绝处理任务而抛出异常。

keepAliveTime

当线程空闲时间达到keepAliveTime,该线程会退出,直到线程数量等于corePoolSize。如果allowCoreThreadTimeout设置为true,则所有线程均会退出直到线程数量为0。

allowCoreThreadTimeout

是否允许核心线程空闲退出,默认值为false。

queueCapacity

任务队列容量。从maxPoolSize的描述上可以看出,任务队列的容量会影响到线程的变化,因此任务队列的长度也需要恰当的设置。

Executors静态工厂创建线程池解释

Executors.newCachedThreadPool();

这种会创建一个目标数目或核心数目为0,最大数目为Integer.MAX_VALUE超时设置1分钟,并且利用SynchronousQueue来存储任务的ThreadPoolExecutor。SynchronousQueue是一种同步移交队列,任务的生产者线程直接将任务移交给任务的消费者线程即工作线程。对于很大的线程池,可以利用SynchronousQueue避免任务的排队。要想将一个元素放入该队列,必须有另一个线程正在等待接收这个元素。当一个新的任务提交后,如果没有线程在等待,且线程池的当前值大小小于最大值,一般ThreadPoolExecutor都会创建一个新的线程。否则就会调用饱和策略来处理。SynchronousQueue这种队列一般用于当线程池无界或者很大的时候采用,目的就是更快的提交任务,充分利用线程池中的工作线程。

Executors.newFixedThreadPool(n);

这种会创建核心数目以及最大数目都是指定初始值的线程池,线程不会超时也就是不会被回收,并且利用无界的(最大值是Integer.MAX_VALUE)的LinkedBlockingQueue来存储任务的ThreadPoolExecutor。

Executors.newSingleThreadExecutor();

这种会创建核心数目以及最大数目都是1的线程池,线程不会超时也就是不会被回收,并且利用无界的(最大值是Integer.MAX_VALUE)的LinkedBlockingQueue来存储任务的ThreadPoolExecutor。

饱和策略解释:
当有界队列被填满后,就需要考虑如何对于再次发送的请求处理。

ThreadPoolExecutor中可以通过setRejectedExecutionHandler设置饱和策略。

ThreadPoolExecutor中包含了四种饱和策略:

AbortPolicy, DiscardPolicy,DiscardOldestPolicy和CallerRunsPolicy

AbortPolicy,即中止策略,是默认的饱和策略,该策略将抛出未检查的RejectedExecutionException。

DiscardPolicy,即抛弃策略,会丢弃队列满后请求的任务。

DiscardOldestPolicy,即抛弃最旧的策略,会抛弃下一个将要被执行的任务,然后尝试重新提交新任务。

CallerRunsPolicy,即调用者策略,既不会抛弃任务,也不会抛出异常,而是将任务回退到调用者。它不会在线程池的某个线程执行新提交的任务,而是在一个调用execute的线程中执行该任务。

注意:

1、可以利用ArrayBlockingQueue,有界的LinkedBlockingQueue、PriorityBlockingQueue来设置存储任务的队列界限。

2、利用Executors静态工厂方法创建ThreadPoolExecutor或者直接实例化ThreadPoolExecutor的对象,默认初始的时候线程并不会立即启动,而是等到有任务提交时候才会启动。当然可以调用prestartAllCoreThreads来启动所有的核心线程。

3、在使用线程池中,当任务是相互独立且类型基本上相同的时候,此时才可以设置线程池和工作队列的界限。

本文出自 “在云端的追梦” 博客,请务必保留此出处http://computerdragon.blog.51cto.com/6235984/1212442

Java线程池Executors的更多相关文章

  1. 【Java 多线程】Java线程池类ThreadPoolExecutor、ScheduledThreadPoolExecutor及Executors工厂类

    Java中的线程池类有两个,分别是:ThreadPoolExecutor和ScheduledThreadPoolExecutor,这两个类都继承自ExecutorService.利用这两个类,可以创建 ...

  2. Java 线程池框架核心代码分析--转

    原文地址:http://www.codeceo.com/article/java-thread-pool-kernal.html 前言 多线程编程中,为每个任务分配一个线程是不现实的,线程创建的开销和 ...

  3. Java线程池使用说明

    Java线程池使用说明 转自:http://blog.csdn.net/sd0902/article/details/8395677 一简介 线程的使用在java中占有极其重要的地位,在jdk1.4极 ...

  4. (转载)JAVA线程池管理

    平时的开发中线程是个少不了的东西,比如tomcat里的servlet就是线程,没有线程我们如何提供多用户访问呢?不过很多刚开始接触线程的开发攻城师却在这个上面吃了不少苦头.怎么做一套简便的线程开发模式 ...

  5. Java线程池的那些事

    熟悉java多线程的朋友一定十分了解java的线程池,jdk中的核心实现类为java.util.concurrent.ThreadPoolExecutor.大家可能了解到它的原理,甚至看过它的源码:但 ...

  6. 四种Java线程池用法解析

    本文为大家分析四种Java线程池用法,供大家参考,具体内容如下 http://www.jb51.net/article/81843.htm 1.new Thread的弊端 执行一个异步任务你还只是如下 ...

  7. Java线程池应用

    Executors工具类用于创建Java线程池和定时器. newFixedThreadPool:创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程.在任意点,在大多数 nThread ...

  8. Java线程池与java.util.concurrent

    Java(Android)线程池 介绍new Thread的弊端及Java四种线程池的使用,对Android同样适用.本文是基础篇,后面会分享下线程池一些高级功能. 1.new Thread的弊端执行 ...

  9. [转 ]-- Java线程池使用说明

    Java线程池使用说明 原文地址:http://blog.csdn.net/sd0902/article/details/8395677 一简介 线程的使用在java中占有极其重要的地位,在jdk1. ...

  10. 【Java线程池快速学习教程】

    1. Java线程池 线程池:顾名思义,用一个池子装载多个线程,使用池子去管理多个线程. 问题来源:应用大量通过new Thread()方法创建执行时间短的线程,较大的消耗系统资源并且系统的响应速度变 ...

随机推荐

  1. C语言三子棋

    话说自从大一学C语言后用C语言的巅峰也就是第十二届蓝桥杯了,后续开发什么的都是用的java,搞开发java这样的面向对象语言确实用着更顺手方便点.不过C语言YYDS,"C生万物"嘛 ...

  2. Coursera self-driving2, State Estimation and Localization Week4, LIDAR

    operating principles 工作原理 Velodyne 加州,Hokuyo 日本,SICK 德国 TOF 就是用发出去收到的时间差和光速算距离 basic LIDAR models (2 ...

  3. PHP 程序员学会了 Go 语言就能唬住面试官吗?

    大家好,我是码农先森. 唬住了 50k ,唬不住就 5k .这句话一直是 PHP 程序员之间相互吹捧.吹牛逼的笑点,每次面试过后都会挠挠头上仅剩的几根头发,回想自己是否吹牛逼会过了头.我经常在微信程序 ...

  4. ST-SSL: 用于交通流量预测的时空自监督学习《Spatio-Temporal Self-Supervised Learning for Traffic Flow Prediction》(交通流量预测、时空异质性、自监督、数据增强)

    2023年10月23日,继续论文,好困,想发疯. 论文:Spatio-Temporal Self-Supervised Learning for Traffic Flow Prediction Git ...

  5. 推荐3款卓越的 .NET 开源搜索组件库

    前言 最近有不少同学提问:.NET有哪些开源的搜索组件库可以推荐的吗?,今天大姚给大家推荐3款卓越的 .NET 开源搜索组件库,希望可以帮助到有需要的同学. Elasticsearch .NET El ...

  6. .NET 开源工业级移动端仓库管理系统

    前言 在工业生产中,定制化的软件对于每个环节都至关重要.对于仓库管理,推荐一款开源的仓库管理系统(WMS)解决方案. 这款基于.NET 框架开发的移动应用,提供了全面的仓库操作.订单处理.主数据管理. ...

  7. 开发板、windows、虚拟机互相ping通/ VMNET0、VMNET1、VMNET8释义

    当前环境:板子通过网线连接windows 问题: 我当前的板子可以ping通windows,windows也能ping通ubuntu.但是板子却ping不通ubuntu. 原因: ubuntu通过NA ...

  8. HeaderFile (1.2-1.6) 中 hct.h 使用教程

    下载 HeaderFile 1.2 HCT 是干什么的 辅助数据生成 主干框架 你需要包含必须的头文件 hct.h 此外,你需要实现如下函数: void create() 数据生成函数 void so ...

  9. [OI] 珂朵莉树

    对于一个序列,它有较多重复元素,并且题目需要维护区间修改,维护区间信息,维护整块值域信息的,那么就可以考虑珂朵莉树解决. 主要思想 珂朵莉树将全部相同的颜色块压缩为一组,如对于下述序列: 1 1 1 ...

  10. MyBatis动态增改,多字段模糊查询

    示例: insert insert into bargain_products <trim prefix="(" suffix=")" suffixOve ...