最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java創(chuàng)建線程池為什么一定要用ThreadPoolExecutor

 更新時(shí)間:2022年05月10日 09:13:58   作者:??Java中文社群????  
本文介紹了Java創(chuàng)建線程池為什么一定要用ThreadPoolExecutor,手動(dòng)方式使用ThreadPoolExecutor創(chuàng)建線程池和使用Executors執(zhí)行器自動(dòng)創(chuàng)建線程池,下文更多相關(guān)內(nèi)容需要的小伙伴可以參考一下

前言:

在 Java 語(yǔ)言中,并發(fā)編程都是依靠線程池完成的,而線程池的創(chuàng)建方式又有很多,但從大的分類來(lái)說(shuō),線程池的創(chuàng)建總共分為兩大類:手動(dòng)方式使用ThreadPoolExecutor創(chuàng)建線程池和使用 Executors 執(zhí)行器自動(dòng)創(chuàng)建線程池。 那究竟要使用哪種方式來(lái)創(chuàng)建線程池呢?我們今天就來(lái)詳細(xì)的聊一聊。

先說(shuō)結(jié)論

在 Java 語(yǔ)言中,一定要使用 ThreadPoolExecutor 手動(dòng)的方式來(lái)創(chuàng)建線程池,因?yàn)檫@種方式可以通過(guò)參數(shù)來(lái)控制最大任務(wù)數(shù)和拒絕策略,讓線程池的執(zhí)行更加透明和可控,并且可以規(guī)避資源耗盡的風(fēng)險(xiǎn)。

OOM風(fēng)險(xiǎn)演示

假如我們使用了 Executors 執(zhí)行器自動(dòng)創(chuàng)建線程池的方式來(lái)創(chuàng)建線程池,那么就會(huì)存現(xiàn)線程溢出的風(fēng)險(xiǎn),

以 CachedThreadPool 為例我們來(lái)演示一下:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolExecutorExample {
    static class OOMClass {
        // 創(chuàng)建 1MB 大小的變量(1M = 1024KB = 1024*1024Byte)
        private byte[] data_byte = new byte[1 * 1024 * 1024];
    }
    public static void main(String[] args) throws InterruptedException {
        // 使用執(zhí)行器自動(dòng)創(chuàng)建線程池
        ExecutorService threadPool = Executors.newCachedThreadPool();
        List<Object> list = new ArrayList<>();
        // 添加任務(wù)
        for (int i = 0; i < 10; i++) {
            int finalI = i;
            threadPool.execute(new Runnable() {
                @Override
                public void run() {
                    // 定時(shí)添加
                    try {
                        Thread.sleep(finalI * 200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    // 將 1M 對(duì)象添加到集合
                    OOMClass oomClass = new OOMClass();
                    list.add(oomClass);
                    System.out.println("執(zhí)行任務(wù):" + finalI);
                }
            });
        }
    }
}

第 2 步將 Idea 中 JVM 最大運(yùn)行內(nèi)存設(shè)置為 10M(設(shè)置此值主要是為了方便演示),如下圖所示: 

 以上程序的執(zhí)行結(jié)果如下圖所示: 

 從上述結(jié)果可以看出,當(dāng)線程執(zhí)行了 7 次之后就開始出現(xiàn)OutOfMemoryError內(nèi)存溢出的異常了。

內(nèi)存溢出原因分析

想要了解內(nèi)存溢出的原因,我們需要查看 CachedThreadPool 實(shí)現(xiàn)的細(xì)節(jié),它的源碼如下圖所示:

 構(gòu)造函數(shù)的第 2 個(gè)參數(shù)被設(shè)置成了 Integer.MAX_VALUE,這個(gè)參數(shù)的含義是最大線程數(shù),所以由于 CachedThreadPool 并不限制線程的數(shù)量,當(dāng)任務(wù)數(shù)量特別多的時(shí)候,就會(huì)創(chuàng)建非常多的線程。而上面的 OOM 示例,每個(gè)線程至少要消耗 1M 大小的內(nèi)存,加上 JDK 系統(tǒng)類的加載也要占用一部分的內(nèi)存,所以當(dāng)總的運(yùn)行內(nèi)存大于 10M 的時(shí)候,就出現(xiàn)內(nèi)存溢出的問題了。

使用ThreadPoolExecutor來(lái)改進(jìn)

接下來(lái)我們使用 ThreadPoolExecutor 來(lái)改進(jìn)一下 OOM 的問題,我們使用 ThreadPoolExecutor 手動(dòng)創(chuàng)建線程池的方式,創(chuàng)建一個(gè)最大線程數(shù)為 2,最多可存儲(chǔ) 2 個(gè)任務(wù)的線程池,并且設(shè)置線程池的拒絕策略為忽略新任務(wù),這樣就能保證線程池的運(yùn)行內(nèi)存大小不會(huì)超過(guò) 10M 了,

實(shí)現(xiàn)代碼如下:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
/**
 * ThreadPoolExecutor 演示示例
 */
public class ThreadPoolExecutorExample {
    static class OOMClass {
        // 創(chuàng)建 1MB 大小的變量(1M = 1024KB = 1024*1024Byte)
        private byte[] data_byte = new byte[1 * 1024 * 1024];
    }

    public static void main(String[] args) throws InterruptedException {
        // 手動(dòng)創(chuàng)建線程池,最大線程數(shù) 2,最多存儲(chǔ) 2 個(gè)任務(wù),其他任務(wù)會(huì)被忽略
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 2,
                0L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(2),
                new ThreadPoolExecutor.DiscardPolicy()); // 拒絕策略:忽略任務(wù)
        List<Object> list = new ArrayList<>();
        // 添加任務(wù)
        for (int i = 0; i < 10; i++) {
            int finalI = i;
            threadPool.execute(new Runnable() {
                @Override
                public void run() {
                    // 定時(shí)添加
                    try {
                        Thread.sleep(finalI * 200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    // 將 1m 對(duì)象添加到集合
                    OOMClass oomClass = new OOMClass();
                    list.add(oomClass);
                    System.out.println("執(zhí)行任務(wù):" + finalI);
                }
            });
        }
        // 關(guān)閉線程池
        threadPool.shutdown();
        // 檢測(cè)線程池的任務(wù)執(zhí)行完
        while (!threadPool.awaitTermination(3, TimeUnit.SECONDS)) {
            System.out.println("線程池中還有任務(wù)在處理");
        }
    }
}

以上程序的執(zhí)行結(jié)果如下圖所示: 

 從上述結(jié)果可以看出,線程池從開始執(zhí)行到執(zhí)行結(jié)束都沒有出現(xiàn) OOM 的異常,這就是手動(dòng)創(chuàng)建線程池的優(yōu)勢(shì)。

其他創(chuàng)建線程池的問題

除了 CachedThreadPool 線程池之外,其他使用 Executors 自動(dòng)創(chuàng)建線程池的方式,也存在著其他一些問題,

比如 FixedThreadPool 它的實(shí)現(xiàn)源碼如下: 

而默認(rèn)情況下任務(wù)隊(duì)列LinkedBlockingQueue的存儲(chǔ)容量是 Integer.MAX_VALUE,也是趨向于無(wú)限大

如下圖所示: 

 這樣就也會(huì)造成,因?yàn)榫€程池的任務(wù)過(guò)多而導(dǎo)致的內(nèi)存溢出問題。其他幾個(gè)使用 Executors 自動(dòng)創(chuàng)建線程池的方式也存在此問題,這里就不一一演示了。

總結(jié)

線程池的創(chuàng)建方式總共分為兩大類:手動(dòng)使用 ThreadPoolExecutor 創(chuàng)建線程池和自動(dòng)使用 Executors 執(zhí)行器創(chuàng)建線程池的方式。其中使用 Executors 自動(dòng)創(chuàng)建線程的方式,因?yàn)榫€程個(gè)數(shù)或者任務(wù)個(gè)數(shù)不可控,可能會(huì)導(dǎo)致內(nèi)存溢出的風(fēng)險(xiǎn),所以在創(chuàng)建線程池時(shí),建議使用 ThreadPoolExecutor 的方式來(lái)創(chuàng)建。

到此這篇關(guān)于Java創(chuàng)建線程池為什么一定要用ThreadPoolExecutor的文章就介紹到這了,更多相關(guān)Java線程池創(chuàng)建內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java中hasNextInt判斷后無(wú)限循環(huán)輸出else項(xiàng)的解決方法

    java中hasNextInt判斷后無(wú)限循環(huán)輸出else項(xiàng)的解決方法

    這篇文章主要介紹了java中hasNextInt判斷后無(wú)限循環(huán)輸出else項(xiàng)的解決方法的相關(guān)資料,需要的朋友可以參考下
    2016-10-10
  • SSh結(jié)合Easyui實(shí)現(xiàn)Datagrid的分頁(yè)顯示

    SSh結(jié)合Easyui實(shí)現(xiàn)Datagrid的分頁(yè)顯示

    這篇文章主要為大家詳細(xì)介紹了SSh結(jié)合Easyui實(shí)現(xiàn)Datagrid的分頁(yè)顯示的相關(guān)資料,感興趣的小伙伴們可以參考一下
    2016-06-06
  • 淺談Strut2如何對(duì)請(qǐng)求參數(shù)的封裝

    淺談Strut2如何對(duì)請(qǐng)求參數(shù)的封裝

    這篇文章主要介紹了淺談Strut2如何對(duì)請(qǐng)求參數(shù)的封裝,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2017-12-12
  • 多模塊的springboot項(xiàng)目發(fā)布指定模塊的腳本方式

    多模塊的springboot項(xiàng)目發(fā)布指定模塊的腳本方式

    該文章主要介紹了如何在多模塊的SpringBoot項(xiàng)目中發(fā)布指定模塊的腳本,作者原先的腳本會(huì)清理并編譯所有模塊,導(dǎo)致發(fā)布時(shí)間過(guò)長(zhǎng),通過(guò)簡(jiǎn)化腳本,只使用`mvn clean install`命令,可以快速發(fā)布指定模塊及其依賴的模塊
    2025-01-01
  • spring boot集成shiro詳細(xì)教程(小結(jié))

    spring boot集成shiro詳細(xì)教程(小結(jié))

    這篇文章主要介紹了spring boot 集成shiro詳細(xì)教程,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-01-01
  • SpringBoot使用easy-captcha 實(shí)現(xiàn)驗(yàn)證碼登錄功能(解決思路)

    SpringBoot使用easy-captcha 實(shí)現(xiàn)驗(yàn)證碼登錄功能(解決思路)

    文章介紹了如何使用Spring Boot和Easy-Captcha實(shí)現(xiàn)驗(yàn)證碼登錄功能,后端通過(guò)Easy-Captcha生成驗(yàn)證碼并存儲(chǔ)在Redis中,前端獲取驗(yàn)證碼并顯示給用戶,登錄時(shí),前端將用戶輸入的驗(yàn)證碼和標(biāo)識(shí)符發(fā)送到后端進(jìn)行驗(yàn)證,感興趣的朋友跟隨小編一起看看吧
    2025-02-02
  • java中volatile關(guān)鍵字的作用詳解

    java中volatile關(guān)鍵字的作用詳解

    這篇文章主要介紹了java中volatile關(guān)鍵字的作用詳解,volatile可以保證,若一個(gè)線程改變了某塊內(nèi)存的值,其他線程是可見的,以至于其他線程能及時(shí)更新這塊內(nèi)存,需要的朋友可以參考下
    2023-09-09
  • Spring 中優(yōu)雅的獲取泛型信息的方法

    Spring 中優(yōu)雅的獲取泛型信息的方法

    這篇文章主要介紹了Spring 中優(yōu)雅的獲取泛型信息的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • SpringSecurityOAuth2實(shí)現(xiàn)微信授權(quán)登錄

    SpringSecurityOAuth2實(shí)現(xiàn)微信授權(quán)登錄

    微信的登錄功能是用戶注冊(cè)和使用微信的必經(jīng)之路之一,而微信授權(quán)登錄更是方便了用戶的登錄操作,本文主要介紹了SpringSecurityOAuth2實(shí)現(xiàn)微信授權(quán)登錄,感興趣的可以了解一下
    2023-09-09
  • java中BIO、NIO、AIO都有啥區(qū)別

    java中BIO、NIO、AIO都有啥區(qū)別

    這篇文章主要介紹了java中BIO、NIO、AIO都有啥區(qū)別,IO模型就是說(shuō)用什么樣的通道進(jìn)行數(shù)據(jù)的發(fā)送和接收,Java共支持3種網(wǎng)絡(luò)編程IO模式:BIO,NIO,AIO,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-04-04

最新評(píng)論

嘉定区| 迁西县| 谢通门县| 漳浦县| 和顺县| 乐山市| 安陆市| 渭源县| 新沂市| 拉萨市| 广宁县| 岢岚县| 淮南市| 敦化市| 东丽区| 福建省| 光山县| 安溪县| 红安县| 桦川县| 息烽县| 新巴尔虎右旗| 林周县| 武宣县| 安康市| 基隆市| 正宁县| 南丹县| 抚远县| 瑞丽市| 新丰县| 丽水市| 大荔县| 江陵县| 沁水县| 新平| 工布江达县| 禹城市| 九江市| 合阳县| 鄂托克前旗|