?
Java 5.0 就开始自带线程池的实现,其中固定大小的线程池,对普通使用还是很好用的。就是?Executors.newFixedThreadPool?,指需要指定一个大小数目就可以。相对于其他几种方式,易于实现高效稳定的服务器。
?
但是好用归好用,一些需要非常细心的问题,还是需要关注的,尤其是高并发场景,7*24不间断运行场景下。本文就是把这些地方记录下来,在设计和实现时,在这些问题上务必不能马虎,因为这关系到稳定性和效率,且不易通过测试来排查。
?
(1)实现:
?
几种线程池,都是通过 ?monospace; font-size: 12px; line-height: 18px;">ThreadPoolExecutor 来实现的,如下:
?
?
?
newFixedThreadPool?:
?
public static ExecutorService newFixedThreadPool(int paramInt) { return new ThreadPoolExecutor(paramInt, paramInt, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()); }
?
而 LinkedBlockingQueue的实现:
?
public LinkedBlockingQueue() { this(2147483647); }
?
这个默认的构造函数,实际上是有一些问题的(实际是构造了一个大小为 Integer.MAX_VALUE的任务队列)。
?
(2)问题
我们设想一个场景,客户端/服务器工作模式,请求来得很快,服务器端accept之后,将Socket放到了任务队列中,读请求处理,并发送响应。客户端连接来得很快,但处理没有那么快(例如需要IO或大量数学运算),所以来了之后就都排在队列里。一直到2147483647。
?
但是实际上,如果一个新的任务排在第100甚至1000、10000,客户端都可以等待,但是如果排到了 1000,000,客户端还会等待着吗?就像你如果去银行办业务,眼看排队都排到街上了,今天肯定轮不到了,你还会继续等吗?
?
换成计算机的设计语言,客户端连接,按照约定俗成,都是有超时的,开始提交了请求自然会等待,一定时间内得不到响应就超时进入异常处理流程了,那么,服务器队列里那个Socket还有什么意义呢?
?
(3)结论
?
所以说,在设计时,队列的长度是一定要用心设计和考虑的,除了在Demo和简单测试一下的程序里,不要轻易而简单的使用newFixedThreadPool?,要想清楚它的问题,在使用时使用其它方式避免。
?
?
?
?
?
?
?
?