首页 > 其他 > 详细

那些年我们踩到过的坑(一):为ThreadPoolExecutor 指定RejectedExecutionHandler需要注意的坑

时间:2015-05-30 23:55:51      阅读:229      评论:0      收藏:0      [点我收藏+]

昨天下午公司的短信发送服务挂掉,查日志发现有些短信服务提供商的服务器time out。马上联系对方,确认服务已经恢复正常,我们立马重启服务,恢复正常。

 

我们的短信服务是起一个线程T1从redis list去拿消息,然后创建一个发送短信的任务线程扔到线程池里执行,每一个发送短信的任务都会连接服务商的服务,time out就是从这里抛出来的,可是连接time out怎么能导致我们的服务挂掉呢? 还好当时做了thread dump,分析了下dump 文件,发现线程T1挂掉了,看代码发现该线程的run方法块里面只catch住了Exception,极有可能是有Throwable的错误抛了出来,导致该线程意外终止。我当时能够想到的有OutOfMemmory 跟 StackOverflow,经过分析定位到以下我们封装的线程池。

private ThreadPoolExecutor threadPoolTaskExecutor = new ThreadPoolExecutor(30, 100, 30, 
            TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(4), new ThreadFactoryBuilder("SmsServiceManager-threadPoolTaskExecutor"), 
            new RejectedExecutionHandler() {
                @Override
                public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                    if (!executor.isShutdown()) {
                        executor.execute(r);
                    }
                }
            });

 注意该类指定了RejectedExecutionHandler,如果任务被reject那么将任务继续添加到线程池。WTF!!!!真暴力啊,线程池拒绝了你的任务,你不做任何处理又把该任务扔进线程池,这就是stack over flow的原因!!!线程池一共有30个worker线程,当时正好某些服务商的短信服务出问题,所以这30个worker线程一直卡在连接对方服务上,当线程池中任务的数量超过100个,那么后来的任务将会被线程池reject,而你被reject后将该任务再一次扔进线程池,产生死循环直到线程T1栈溢出。

最后我们的解决方案是:

1. 在线程T1的run方法块里面catch住Throwable。

2. 任务被线程池reject后将消息重新放到redis队列里。

 

这两天刚刚接手短信这块,坑很多,且行且小心。

那些年我们踩到过的坑(一):为ThreadPoolExecutor 指定RejectedExecutionHandler需要注意的坑

原文:http://www.cnblogs.com/longzhaoyu/p/4539341.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!