ThreadPoolExecutor异常问题,请大家帮忙看看.

翰斯 发布于 2015/12/25 10:21
阅读 2K+
收藏 1

我的线程池配置是: 
mExecutorPool = new ThreadPoolExecutor(5, 10, 5, TimeUnit.MINUTES, new LinkedBlockingQueue<Runnable>(1));
为啥LinkedBlockingQueue设置为1。是因为看了[url=http://www.jianshu.com/p/f343782f19fc][/url]这篇文章最后的结论。我也刚用这个线程池,只有照搬。

但测试时发现报下列异常:
Exception in thread "Thread-0" java.util.concurrent.RejectedExecutionException: Task hansi.UDPExecutor@1133e2b3 rejected from java.util.concurrent.ThreadPoolExecutor@65685e97[Running, pool size = 10, active threads = 2, queued tasks = 0, completed tasks = 26]
 at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2048)
 at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:821)
 at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1372)
 at hansi.UDPService.receive(UDPService.java:39)
 at hansi.UDPService.run(UDPService.java:65)
 at java.lang.Thread.run(Thread.java:745)
我理解的是:
1.pool size=10: 池里有10个工作线程;
2.active threads = 2: 有两个线程在工作;
3.queued tasks = 0: 没有任务了。
应该还有8个可用线程和queued里还有一个位置,为啥就报异常,无能接受新的任务?
我测试环境的java版本为:jdk1.7.0_79

加载中
0
a
alex
完整的 ThreadPoolExecutor ,最后还有一个入参, 用于表示,线程被拒绝加入线程池,所做的处理;好像,默认是:ThreadPoolExecutor.AbortPolicy();这个表示,被拒的时候,直接抛出异常;也就是你上面贴的异常了;解释一下你这个:new ThreadPoolExecutor(5, 10, 5, TimeUnit.MINUTES, new LinkedBlockingQueue<Runnable>(1)); 的含义:初始5个线程,最大10个,空闲5分钟,缓存为1;那么当 线程 <5 的时候,新加入的线程直接运行,当 >5,的时候,加入缓存,如果缓存也满了,申请增加线程一直到最大的10,如果线程池中的线程都在忙,而且缓存也满了(你这个缓存才1);那么,在新加入线程,就被拒了;从异常的信息分析,和你说的没错,确实当前运行中的就2个线程,还有空余的线程数;是否是发生异常的时间和异常信息抛出的时间之间存在误差?可以将最后一个入参修改为:CallerRunsPolicy 试试看;
翰斯
谢谢你的解释.我后来也查到最后参数有个默认值.只是从异常打印看不出新任务已经把线程池占满了.估计如徐所说,异常打印并没有显示出下问题原因
0
jianglibo
jianglibo

你不妨提供测试的代码,来探讨一下。

翰斯
我觉得与其它地方代码关系不大.我目前把任务队列换成SynQueue也没有报错误。
0
徐春鹏
徐春鹏
Proceed in 3 steps:  
1. If fewer than corePoolSize threads are running, try to  start a new thread with the given command as its first  task.  The call to addWorker atomically checks runState and  workerCount, and so prevents false alarms that would add  threads when it shouldn't, by returning false.  
2. If a task can be successfully queued, then we still need  to double-check whether we should have added a thread  (because existing ones died since last checking) or that  the pool shut down since entry into this method. So we  recheck state and if necessary roll back the enqueuing if  stopped, or start a new thread if there are none.  
3. If we cannot queue task, then we try to add a new  thread.  If it fails, we know we are shut down or saturated  and so reject the task. 


/**  * Invokes the rejected execution handler for the given command.  * Package-protected for use by ScheduledThreadPoolExecutor.  */ final void reject(Runnable command) { handler.rejectedExecution(command, this);
}
调用这个的时候  传了个当前对象引用, 然后打印


public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { throw new RejectedExecutionException("Task " + r.toString() + " rejected from " +
                                         e.toString());
}
然后扔了个 异常出去,都是引用的 , 意思就是说 里面的线程数值一直变化的。

翰斯
我增加最后的参数使用决绝新任务的策略就行.谢谢大家!
徐春鹏
徐春鹏
回复 @alex : 嗯 我看并没有保存当时的现场。
a
alex
那你的意思是说,这里抛出的异常 中,说明的线程数,并不是发生异常那个时间的?
返回顶部
顶部