關於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個線程,才能消化掉這個創建任務速度。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章