线程池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



0 0