欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

前言:

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

先說結(jié)論

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

OOM風險演示

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

以 CachedThreadPool 為例我們來演示一下:

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í)行器自動創(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() {
                    // 定時添加
                    try {
                        Thread.sleep(finalI * 200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    // 將 1M 對象添加到集合
                    OOMClass oomClass = new OOMClass();
                    list.add(oomClass);
                    System.out.println("執(zhí)行任務(wù):" + finalI);
                }
            });
        }
    }
}

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

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

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

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

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

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

使用ThreadPoolExecutor來改進

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

實現(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 {
        // 手動創(chuàng)建線程池,最大線程數(shù) 2,最多存儲 2 個任務(wù),其他任務(wù)會被忽略
        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() {
                    // 定時添加
                    try {
                        Thread.sleep(finalI * 200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    // 將 1m 對象添加到集合
                    OOMClass oomClass = new OOMClass();
                    list.add(oomClass);
                    System.out.println("執(zhí)行任務(wù):" + finalI);
                }
            });
        }
        // 關(guān)閉線程池
        threadPool.shutdown();
        // 檢測線程池的任務(wù)執(zhí)行完
        while (!threadPool.awaitTermination(3, TimeUnit.SECONDS)) {
            System.out.println("線程池中還有任務(wù)在處理");
        }
    }
}

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

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

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

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

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

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

如下圖所示: 

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

總結(jié)

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

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

相關(guān)文章

  • Spring Boot集成MyBatis實現(xiàn)通用Mapper的配置及使用

    Spring Boot集成MyBatis實現(xiàn)通用Mapper的配置及使用

    關(guān)于MyBatis,大部分人都很熟悉。MyBatis 是一款優(yōu)秀的持久層框架,它支持定制化 SQL、存儲過程以及高級映射。這篇文章主要介紹了Spring Boot集成MyBatis實現(xiàn)通用Mapper,需要的朋友可以參考下
    2018-08-08
  • 淺談Java設(shè)計模式系列-裝飾器模式

    淺談Java設(shè)計模式系列-裝飾器模式

    這篇文章主要介紹了Java設(shè)計模式系列-裝飾器模式,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-03-03
  • Java項目防止SQL注入的幾種方式

    Java項目防止SQL注入的幾種方式

    SQL注入是一種常見的攻擊方式,黑客試圖通過操縱應(yīng)用程序的輸入來執(zhí)行惡意SQL查詢,從而繞過認證和授權(quán),竊取、篡改或破壞數(shù)據(jù)庫中的數(shù)據(jù),本文主要介紹了Java項目防止SQL注入的幾種方式,感興趣的可以了解一下
    2023-12-12
  • Spring中Bean的三種實例化方式詳解

    Spring中Bean的三種實例化方式詳解

    這篇文章主要給大家介紹了關(guān)于Spring中實例化bean的三種方式:構(gòu)造方法、靜態(tài)工廠和實例工廠,對我們學習有一定的參考價值,需要的小伙伴可以了解一下
    2022-06-06
  • Spring學習通過AspectJ注解方式實現(xiàn)AOP操作

    Spring學習通過AspectJ注解方式實現(xiàn)AOP操作

    這篇文章主要為大家介紹了Spring學習通過AspectJ注解方式實現(xiàn)AOP操作,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-05-05
  • JAVA集合框架工具類自定義Collections集合方法

    JAVA集合框架工具類自定義Collections集合方法

    今天小編就為大家分享一篇關(guān)于JAVA集合框架工具類自定義Collections集合方法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • Java獲取中文拼音、中文首字母縮寫和中文首字母的示例

    Java獲取中文拼音、中文首字母縮寫和中文首字母的示例

    本文主要介紹了Java獲取中文拼音、中文首字母縮寫和中文首字母,具有一定的參考價值,感興趣的小伙伴們可以參考一下。
    2016-10-10
  • java?String到底有多長?String超出長度該如何解決

    java?String到底有多長?String超出長度該如何解決

    在Java中,由于字符串常量池的存在,String常量長度限制取決于String常量在常量池中的存儲大小,下面這篇文章主要給大家介紹了關(guān)于java?String到底有多長?String超出長度該如何解決的相關(guān)資料,需要的朋友可以參考下
    2023-01-01
  • Java日常練習題,每天進步一點點(41)

    Java日常練習題,每天進步一點點(41)

    下面小編就為大家?guī)硪黄狫ava基礎(chǔ)的幾道練習題(分享)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧,希望可以幫到你
    2021-07-07
  • Spring實戰(zhàn)之協(xié)調(diào)作用域不同步的Bean操作示例

    Spring實戰(zhàn)之協(xié)調(diào)作用域不同步的Bean操作示例

    這篇文章主要介紹了Spring實戰(zhàn)之協(xié)調(diào)作用域不同步的Bean操作,結(jié)合實例形式分析了Spring協(xié)調(diào)作用域不同步的Bean相關(guān)配置及使用技巧,需要的朋友可以參考下
    2019-11-11

最新評論