采用ScheduledThreadPoolExecutor执行定时重试任务时内存溢出的分析及解决

时间:2022-09-25 02:56:21

采用ScheduledThreadPoolExecutor执行定时重试任务时内存溢出的分析及解决

摘 要:开发JavaWeb项目中发现服务之间的调用存在超时情况,由于涉及的处理逻辑全部是异步,引入定时重试的机制,重试工具选择了JDK自带的ScheduledThreadPoolExecutor。当A服务依赖B服务,B服务由于在业务高峰期处理能力降低,导致大量A服务过来的请求超时,A加入了超时重试机制,间隔时间根据重试次数的多少来决定,次数越多,两次重试之间间隔的时间越多,此时的业务高峰也会给A带来大量请求,大量的超时会导致重试队列迅速堆积,直到内存溢出。该文从线程池工作机制、ScheduledThreadPoolExecutor实例的创建,获取重试任务的过程以及提交任务的过程角度分析,并通过源代码的剖析和测试工具MyEclipse进行演示测试内存泄露的情况,得出避免内存泄露的解决方案。

关键词:ScheduledThreadPoolExecutor 线程池 内存溢出

中图分类号:TP3 文献标识码:A 文章编号:1672-3791(2016)03(a)-0015-03

1 ScheduledThreadPoolExecutor实例的创建过程及线程池工作机制

1.1 ScheduledThreadPoolExecutor实例的创建过程

重试工具选择了JDK自带的ScheduledThreadPoolExecutor。ScheduledThreadPoolExecutor实例的创建过程如下:ScheduledThreadPoolExecutor实例的创建过程如下:(1)获取当前机器上处理器的数量;(2)使用Google的ThreadFactoryBuiler创建指定格式名称的线程,以方便查看问题;(3)有需要被拒绝的任务时,抛出异常;(4)创建定时任务池;打开MyEclipse工具显示相对的代码:int corePoolSize=Runtime.getRuntime().availableProcessors();

ThreadFactory tf=new ThreadFactoryBuilder().setNameFormat("FailureRetryTask-pool-%d").build();

RejectedExecutionHandler handler=new ThreadPoolExecutor.AbortPolicy();

ScheduledThreadPoolExecutor taskService=new ScheduletThreadPooExecutor(corePoolSize,tf,handler);

线程池就是多个线程在一个队列中取任务执行,提交的任务会被放入队列中等待线程执行,故队列要设置一个大小。线程池同样会根据任务繁忙程度来动态调整连接数,空闲时保持最小连接数,繁忙时增加连接,但不会超过上限,具有伸缩性,线程的创建和销毁也需要消耗系统资源,线程的连接重用就可以避免这部分损失,具有重用性。

1.2 线程池工作机制

线程获取任务的策略就是如果当前线程池运行状态正常,则阻塞等待任务,否则直接返回或等待有限时间后返回。线程池中线程的主要任务就是获取任务,然后执行,然后再去获取任务,如此循环,这就实现了线程池中线程的可重用。

Worker封装了任务,同时创建了新的线程,并被添加到集合workers中,这个workers其实就是最核心的线程池。通过run方法实现重用。private final HashSet workers=new HashSet();

public void run(){

try{

Runnable task=firstTask;

firstTask=null;

while(task!=null||(task=getTask())!=null){

runTask(task);

task=null;}}

finally{

workerDone(this);

}

}

Runnable getTask(){

for(;;){

try{

int state=runState;

if(state>SHUTDOWN){return null;}

Runnable r;

if(state==SHUTDOWN){r=workQueue.poll();}

else if(poolSize>corePoolSize||allowCoreThreadTimeOut){

r=workQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS);

}else{r=workQueue.take();}

if(r!=null){return r;}

if(workerCanExit()){

if(runState>=SHUTDOWN){interruptIdleWorkers();}

return null;

}

}

catch(InterruptedException ie){}

}

}

private boolean workerCanExit(){

final RenntrantLock mainLock=this.mainLock;

上一篇:齐溪 不介意靠近“悬崖” 下一篇:王俭 T20跨界蓝海的领航人