关于ThreadPool抛出OOM问题

关于ThreadPool抛出OOM问题

案例

最近在学习Java调优,有个案例是ThraadPool导致OOM,在不了解线程池的情况很难看出问题来。
代码片.

package com.example.demo;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TestThreadPool {
    public static void main(String[] arr) {
        ExecutorService executorService = new ThreadPoolExecutor(1, 2,
                0, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>());

        for (; ; ) {
            Person person = new Person();
            executorService.execute(() -> {
                person.doingSomething();

            });
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    static class Person {
        public String name;
        public Integer sex;
        public String age;

        public void doingSomething() {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

这段代码很简单,创建一个线程很少,使用一个无界缓存队列的线程池,然后频繁的给线程池加执行任务,很显然,在jvm内存设置的不够大的情况,抛出outOfMemory是迟早的事情,只是这个时间有点长。

不信执行 java -Xms20M -Xmx20M -XX:+PrintGC com.example.demo.TestThreadPool 试试
为了快速试错,将堆大小改成20M。

下面花了4个小时终于等到错误结果了:
在这里插入图片描述

为什么会OOM

我们来分析一下,首先线程池执行execute时,并不是马上执行任务,它是先把它插入线程池里面的队列,然后排队由线程池的线程执行。你可以把它想象成一个蓄水池,需要执行的任务是水,池子一边进水,一边放水,什么情况下会发生水的溢出呢?很简单,进水的速度比放水的速度还快时,水就会溢出。我们再来回到代码,上面的代码每100毫秒就会加一个执行任务,那么一秒钟的时间它加入任务数是1000/100=10个,然后这个线程池最多有两个执行线程,每个线程执行的时间需要3秒,那它1秒钟能释放的任务数是2*1000/3000=2/3个,10>2/3,进来的速度明显比释放的快多了,所以它任务队列是一直增长的,在任务里面需要使用的对象,jvm是不会把它回收的,所以上面的例子中,创建person实例而不被gc回收的数量会越来越多,最终会把堆内存撑爆。

那么要怎么样才能解决这个问题呢?这个没有100%可以保证解决的办法,但是可以从两个方面去处理,要么减少加入的任务数量(但是很多程序它的压力就是那么大的没法优化,可能只能想其他办法,通过负载均衡加多个更多的服务),要么增加线程数量(线程数也不是越多越好的),那如果采用增加线程的方式,那要加多少线程才够呢?这个问题就要需要用到小学数学知识了,任务增加的速率为1000/100=10,一个线程处理的任务的速率是1*1000/3000=1/3,这个线程池一共至少需要10/(1/3)=30个线程,才能消化掉这个创建任务速度。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值