说起这个异常那得追溯到十几个月以前的初夏的夜晚!~
作为有志青年此时虽已是深夜我们依然为系统拆分奋斗着。
xx同事正在压测。我目不转睛的盯着订单号服务的日志,忽然,java.util.concurrent.RejectedExecutionException: Thread pool is EXHAUSTED! 蹦了粗来。果断ctrl+c,由于当时对dubbo使用不深,也没有研究过源码,所以是一头雾水,百思不得骑姐。
后来硬着头皮看了下源码,于是乎~
了解到dubbo内部核心线程池:
以fixThreadPool举栗子:
public class FixedThreadPool implements ThreadPool { public Executor getExecutor(URL url) { String name = url.getParameter(Constants.THREAD_NAME_KEY, Constants.DEFAULT_THREAD_NAME); int threads = url.getParameter(Constants.THREADS_KEY, Constants.DEFAULT_THREADS); int queues = url.getParameter(Constants.QUEUES_KEY, Constants.DEFAULT_QUEUES); return new ThreadPoolExecutor(threads, threads, 0, TimeUnit.MILLISECONDS, queues == 0 ? new SynchronousQueue<Runnable>() : (queues < 0 ? new LinkedBlockingQueue<Runnable>() : new LinkedBlockingQueue<Runnable>(queues)), new NamedThreadFactory(name, true), new AbortPolicyWithReport(name, url)); } }在创建核心线程池的时候有个queues的参数,通过他来判断使用SynchronousQueue还是LinkedBlockingQueue,关于这二位区别java doc已做说明不再做赘述。public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { String msg = String.format("Thread pool is EXHAUSTED!" + " Thread Name: %s, Pool Size: %d (active: %d, core: %d, max: %d, largest: %d), Task: %d (completed: %d)," + " Executor status:(isShutdown:%s, isTerminated:%s, isTerminating:%s), in %s://%s:%d!" , threadName, e.getPoolSize(), e.getActiveCount(), e.getCorePoolSize(), e.getMaximumPoolSize(), e.getLargestPoolSize(), e.getTaskCount(), e.getCompletedTaskCount(), e.isShutdown(), e.isTerminated(), e.isTerminating(), url.getProtocol(), url.getIp(), url.getPort()); logger.warn(msg); throw new RejectedExecutionException(msg); }于是,之前在生产商看到的异常很容易就复现出来:public class DubboTest { private static final Logger LOGGER= LoggerFactory.getLogger(DubboTest.class); public static void testUpdate() { URL url = new URL("Dubbo", "localhost", 9003); ExecutorService executor1 = new ThreadPoolExecutor(200, 20000, 60L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(300), // new SynchronousQueue(), dubbo缺省使用这个workQueue new NamedThreadFactory("Dubbo", true), new AbortPolicyWithReport("dubbo", url)); for (int i = 0; i < 50000000; i++) { // System.out.println("----------"+i); executor1.submit(new Runnable() { @Override public void run() { System.out.println("heieieiei"); try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "----doing....."); } }); // System.out.println("###########"+i); } } }当然通过配置queue来解决线程池溢出的问题仅仅是缓兵之计,还是要从根源上优化底层逻辑,比如底层sql.