线上同事写的线程池
private static ThreadFactory pushThreadFactory = new ThreadFactoryBuilder().setNameFormat("event-redirect-%d").build();
private static ThreadPoolExecutor appPushExecutor = new ThreadPoolExecutor(8, 16,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(),pushThreadFactory, new ThreadPoolExecutor.AbortPolicy());
场景解读:
处理微信回调事件,采用了上图异步线程处理的方式,然后异步线程处理调用了一个很耗时的接口,大概5到10s。
到了高峰期的时候,发现,微信回调一直超时,超过了微信回调等待时间5秒
问题分析:
ThreadPoolExecutor线程池中各参数解读
corePoolSize:核心线程池大小
maximumPoolSize :最大线程池大小(当阻塞队列满了,才会扩大到最大线程池大小)
keepAliveTime :线程最大空闲时间
unitTimeUnit :时间单位
BlockingQueue<Runnable> workQueue ::线程等待队列
ThreadFactory threadFactory: 线程创建工厂
RejectedExecutionHandler handler :拒绝策略
所以根据参数配置可以分析:阻塞队列用到了new LinkedBlockingQueue<>(),默认的队列大小是Integer的最大值,等同于无界队列,也就是线程永远接近只有8个,不会扩大到16个,
导致了高峰期回调都阻塞在队列中,随着内存飙升,应用进行fullGc,处理缓慢,超过了微信的回调5秒限制。
解决方案:
根据业务场景:我们调整如下
private static ThreadFactory pushThreadFactory = new ThreadFactoryBuilder().setNameFormat("event-redirect-%d").build();
private static ThreadPoolExecutor appPushExecutor = new ThreadPoolExecutor(32, 64,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(5000),pushThreadFactory, new ThreadPoolExecutor.AbortPolicy());
调整说明:因为耗时的是io操作,所以我们大概按4核,cpu核数/0.1=40调整为64
如果是cpu密集型的,才应该设置得跟cpu接近的核数。