线程池ThreadPoolExecutor使用
来源:互联网 发布:淘宝apass会员资格 编辑:程序博客网 时间:2024/05/16 06:48
1. 说明
最近笔者在开发时,遇到了这样的问题。当笔者通过WEB界面删除某一条记录时,系统老是报“系统出错”,并且想到删除的数据并没有删除掉。查看Tomcat的日志,发现报了以下的错误:
java.util.concurrent.RejectedExecutionExceptionat java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(Unknown Source)at java.util.concurrent.ThreadPoolExecutor.reject(Unknown Source)at java.util.concurrent.ThreadPoolExecutor.execute(Unknown Source)
如果对线程熟悉的读者,一眼就会知道,这样的错是跟线程有关系的,也就是说我在执行一条删除记录时,该删除代码被线程拒绝执行了。那就其了怪了,为什么好好的,线程会拒绝执行我的代码呢?通过跟踪代码,笔者发现,我们系统对于线程的处理都是难过线程池的调用的,也就是说当前的处理可能是超出线程池的大小,所以才被拒绝执行。好了,笔者知道了问题所在,修改了线程池的大小,果真问题解决了。但为了进行一步了解线程池,今天笔者就总结了一下线程池的用法。
2. 介绍ThreadPoolExecutor
通过上面的报错信息,我们也就知道,线程池的类就是java.util.concurrent.ThreadPoolExecutor.通过源代码,我们可以看到这个方法的函数如下:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), handler); }我们可以看到,总共有六个参数,那么这几个对数的作用如何呢?笔者通过下面的表格来说明:
这几个参数的作用,网上还给出了以下几点说明:
1) 如果线程池中运行的线程 小于corePoolSize ,即使线程池中的线程都处于空闲状态,也要 创建新的线程 来处理被添加的任务。
2) 如果线程池中运行的线程大于等于corePoolSize,但是缓冲队列 workQueue未满 ,那么任务被放入缓冲队列 。
3) 如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满(即无法将请求加入队列 ),并且线程池中的数量小于maximumPoolSize,建新的线程 来处理被添加的任务。
4) 如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maximumPoolSize ,那么通过 handler 所指定的策略来处理此任务。
5) 当线程池中的线程数量大于corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止 。这样,线程池可以动态的调整池中的线程数。
也就是说处理任务的优先级为:corePoolSize、任务队列workQueue、最大线程maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。
在使用线程池时,经常会抛出这两个错误:IllegalArgumentException、NullPointerException。那么在什么情况下抛出IllegalArgumentException,又在什么情况下抛出NullPointerException错误呢?下面表格给出说明:
3. 例子说明
1) 首先,创建一个通用的线程池。这里主要就是new一个ThreadPoolExexutor的类,对于线程拒绝处理任务的处理,我们给出了两个方案,分别是:使用有界队列策略和使用无界队列策略。无界队列,我们使用LinkedBlockingQueue;有界队列是ArrayBlockingQueue.这里需要说明的是,使用无界queuw可能会耗尽系统资源,使用有界queue可能不能很好的满足性能,需要调用线程数和queue大小。
import java.util.concurrent.ArrayBlockingQueue;import java.util.concurrent.BlockingQueue;import java.util.concurrent.LinkedBlockingQueue;import java.util.concurrent.RejectedExecutionHandler;import java.util.concurrent.ThreadPoolExecutor;import java.util.concurrent.TimeUnit;/** * 创建线程池 * * @author owenwilliam * @Date 2017-4-17 * */public class ThreadPool{public static final int ARRAY_QUEUE = 0; //ArrayBlockingQueue 有界队列策略public static final int LINKED_QUEUE = 1; //LinkedBlockingQueue 使用无界队列策略private ThreadPoolExecutor executor;private BlockingQueue<Runnable> workQueue;/** * @param workQueneSize * 队列长度 * @param coreSize * 主线程数 * @param maxSize * 最大线程数 * @param queueType * 队列类型 */public ThreadPool(final int workQueneSize, final int coreSize,final int maxSize, int queueType){this(workQueneSize, coreSize, maxSize, queueType, null);}/** * * @param workQueneSize * 队列长度 * @param coreSize * 主线程数 * @param maxSize * 最大线程数 * @param queueType * 队列类型 * @param policy * 处理策略 */public ThreadPool(final int workQueneSize, final int coreSize,final int maxSize, int queueType, RejectedExecutionHandler policy){workQueue = createQueue(queueType, workQueneSize);executor = new ThreadPoolExecutor(coreSize, maxSize, 60,TimeUnit.SECONDS, workQueue, policy != null ? policy: new ThreadPoolExecutor.AbortPolicy());}public void execute(Runnable runnable){if (workQueue.size() > 4){System.out.println("当前等待线程大小:'"+runnable.getClass().getSimpleName()+ "':"+workQueue.size());}executor.execute(runnable);}/** * 创建队列,选择不同和队列策略 * ArrayBlockingQueue 有界队列策略 * LinkedBlockingQueue 使用无界队列策略 * @param queueType * @param queueSize * @return */private BlockingQueue<Runnable> createQueue(int queueType, int queueSize){return queueType == LINKED_QUEUE ? new LinkedBlockingQueue<Runnable>(queueSize) : new ArrayBlockingQueue<Runnable>(queueSize);}public BlockingQueue<Runnable> getQueue(){return executor.getQueue();}}
2) 创建一个线程。
/** * 单个线程 * @author owenwilliam * @Date 2017-4-17 * */public class ThreadRunnable implements Runnable{String name;public ThreadRunnable(String name){this.name = name;}@Overridepublic void run(){// 处理一个任务,这里的处理方式太简单了,仅仅是一个打印语句System.out.println("start .." + name);try{// 便于观察,等待一段时间Thread.sleep(2000);} catch (Exception e){e.printStackTrace();}}}
3) 创建一个类调用线程池和线程。
/** * 使用线程池 * * @author owenwilliam * @Date 2017-4-17 * */public class USThreadPool{private ThreadPool tp;private static USThreadPool pool = new USThreadPool();private USThreadPool(){int workQueneSize = 80;int coreSize = 4;int maxSize = 10;//创建线程池tp = new ThreadPool(workQueneSize, coreSize, maxSize,ThreadPool.ARRAY_QUEUE);}public static USThreadPool getPool(){return pool;}public void execute(Runnable runnable){tp.execute(runnable);}public void execute(String name){execute(new ThreadRunnable(name));}}
4) 最后写一个测试类。
/** * 测试线程 * * @author owenwilliam * @Date 2017-4-17 * */public class TestThread{public static void main(String[] args){for (int i = 0; i < 10; i++){USThreadPool.getPool().execute("num:" + i);}}}
4. 执行结果
源码地址:git@github.com:owenwilliam/ThreadPool.git
- 线程池ThreadPoolExecutor使用
- 线程池ThreadPoolExecutor使用简介
- 线程池ThreadPoolExecutor使用简介
- 线程池ThreadPoolExecutor使用简介
- 线程池ThreadPoolExecutor使用简介
- 线程池ThreadPoolExecutor使用简介
- 线程池ThreadPoolExecutor使用简介
- 线程池ThreadPoolExecutor使用简介
- 线程池ThreadPoolExecutor使用简介
- 线程池ThreadPoolExecutor使用简介
- 线程池ThreadPoolExecutor使用简介
- 线程池ThreadPoolExecutor使用简介
- 线程池ThreadPoolExecutor使用简介
- 线程池ThreadPoolExecutor使用简介
- ThreadPoolExecutor线程池的使用
- ThreadPoolExecutor线程池使用介绍
- 线程池ThreadPoolExecutor使用简介
- 线程池ThreadPoolExecutor使用简介
- python中的私有变量
- Protocol 协议
- Oracle数据库中字符串相关字段类型辨析
- call,apply与bind方法的区别
- 53.性能调优之使用 fastutil 优化数据格式
- 线程池ThreadPoolExecutor使用
- http状态码
- Java反射机制
- nslookup 使用方法简介
- linux用rpm命令安装jdk
- 树莓派--开坑
- [多项式] COGS 有标号的二分图计数系列
- Android 开机启动
- 【LeetCode】【Python】【C++】2. Add Two Numbers代码实现