自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

線程池,坑中之王 !

開發(fā) 前端
線程池是 Java 中處理多線程的強(qiáng)大工具,但它不僅僅是“直接用就完事”的工具。很多小伙伴在用線程池時(shí),因?yàn)榕渲貌划?dāng)或忽略細(xì)節(jié),踩過許多坑。

前言

線程池是 Java 中處理多線程的強(qiáng)大工具,但它不僅僅是“直接用就完事”的工具。

很多小伙伴在用線程池時(shí),因?yàn)榕渲貌划?dāng)或忽略細(xì)節(jié),踩過許多坑。

今天跟大家一起聊聊線程池中容易踩的 10 個(gè)坑,以及如何避免這些坑,希望對(duì)你會(huì)有所幫助。

1. 直接使用 Executors 創(chuàng)建線程池

許多初學(xué)者在創(chuàng)建線程池時(shí),直接使用 Executors 提供的快捷方法:

ExecutorService executor = Executors.newFixedThreadPool(10);

問題在哪?

  • 無(wú)界隊(duì)列:newFixedThreadPool 使用的隊(duì)列是 LinkedBlockingQueue,它是無(wú)界隊(duì)列,任務(wù)堆積可能會(huì)導(dǎo)致內(nèi)存溢出。
  • 線程無(wú)限增長(zhǎng):newCachedThreadPool 會(huì)無(wú)限創(chuàng)建線程,在任務(wù)量激增時(shí)可能耗盡系統(tǒng)資源。

示例:內(nèi)存溢出的風(fēng)險(xiǎn)

ExecutorService executor = Executors.newFixedThreadPool(2);
for (int i = 0; i < 1000000; i++) {
    executor.submit(() -> {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
}

任務(wù)數(shù)遠(yuǎn)大于線程數(shù),導(dǎo)致任務(wù)無(wú)限堆積在隊(duì)列中,最終可能導(dǎo)致 OutOfMemoryError。

解決辦法

使用 ThreadPoolExecutor,并明確指定參數(shù):

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    2,
    4,
    60L,
    TimeUnit.SECONDS,
    new ArrayBlockingQueue<>(100), // 有界隊(duì)列
    new ThreadPoolExecutor.AbortPolicy() // 拒絕策略
);

2. 錯(cuò)誤配置線程數(shù)

很多人隨意配置線程池參數(shù),比如核心線程數(shù) 10,最大線程數(shù) 100,看起來沒問題,但這可能導(dǎo)致性能問題或資源浪費(fèi)。

示例:錯(cuò)誤配置導(dǎo)致的線程過載

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    10, // 核心線程數(shù)
    100, // 最大線程數(shù)
    60L,
    TimeUnit.SECONDS,
    new ArrayBlockingQueue<>(10)
);

for (int i = 0; i < 1000; i++) {
    executor.submit(() -> {
        try {
            Thread.sleep(5000); // 模擬耗時(shí)任務(wù)
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
}

這種配置在任務(wù)激增時(shí),會(huì)創(chuàng)建大量線程,系統(tǒng)資源被耗盡。

正確配置方式

根據(jù)任務(wù)類型選擇合理的線程數(shù):

  • CPU 密集型:線程數(shù)建議設(shè)置為 CPU 核心數(shù) + 1。
  • IO 密集型:線程數(shù)建議設(shè)置為 2 * CPU 核心數(shù)。

示例:

int cpuCores = Runtime.getRuntime().availableProcessors();
ThreadPoolExecutor executor = new ThreadPoolExecutor(
    cpuCores + 1,
    cpuCores + 1,
    60L,
    TimeUnit.SECONDS,
    new ArrayBlockingQueue<>(50)
);

3. 忽略任務(wù)隊(duì)列的選擇

任務(wù)隊(duì)列直接影響線程池的行為。如果選錯(cuò)隊(duì)列類型,會(huì)帶來很多隱患。

常見隊(duì)列的坑

  • 無(wú)界隊(duì)列:任務(wù)無(wú)限堆積。
  • 有界隊(duì)列:隊(duì)列滿了會(huì)觸發(fā)拒絕策略。
  • 優(yōu)先級(jí)隊(duì)列:容易導(dǎo)致高優(yōu)先級(jí)任務(wù)頻繁搶占低優(yōu)先級(jí)任務(wù)。

示例:任務(wù)堆積導(dǎo)致問題

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    2,
    4,
    60L,
    TimeUnit.SECONDS,
    new LinkedBlockingQueue<>()
);

for (int i = 0; i < 100000; i++) {
    executor.submit(() -> System.out.println(Thread.currentThread().getName()));
}

改進(jìn)方法:用有界隊(duì)列,避免任務(wù)無(wú)限堆積。

new ArrayBlockingQueue<>(100);

4. 忘記關(guān)閉線程池

有些小伙伴用完線程池后,忘記調(diào)用 shutdown(),導(dǎo)致程序無(wú)法正常退出。

示例:線程池未關(guān)閉

ExecutorService executor = Executors.newFixedThreadPool(5);
executor.submit(() -> System.out.println("任務(wù)執(zhí)行中..."));
// 線程池未關(guān)閉,程序一直運(yùn)行

正確關(guān)閉方式

executor.shutdown();
try {
    if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
        executor.shutdownNow();
    }
} catch (InterruptedException e) {
    executor.shutdownNow();
}

5. 忽略拒絕策略

當(dāng)任務(wù)隊(duì)列滿時(shí),線程池會(huì)觸發(fā)拒絕策略,很多人不知道默認(rèn)策略(AbortPolicy)會(huì)直接拋異常。

示例:任務(wù)被拒絕

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    1,
    1,
    60L,
    TimeUnit.SECONDS,
    new ArrayBlockingQueue<>(2),
    new ThreadPoolExecutor.AbortPolicy() // 默認(rèn)策略
);

for (int i = 0; i < 10; i++) {
    executor.submit(() -> System.out.println("任務(wù)"));
}

執(zhí)行到第四個(gè)任務(wù)時(shí)會(huì)拋出 RejectedExecutionException。

改進(jìn):選擇合適的策略

  • CallerRunsPolicy:提交任務(wù)的線程自己執(zhí)行。
  • DiscardPolicy:直接丟棄新任務(wù)。
  • DiscardOldestPolicy:丟棄最老的任務(wù)。

6. 任務(wù)中未處理異常

線程池中的任務(wù)拋出異常時(shí),線程池不會(huì)直接拋出,導(dǎo)致很多問題被忽略。

示例:異常被忽略

executor.submit(() -> {
    throw new RuntimeException("任務(wù)異常");
});

解決方法

捕獲任務(wù)內(nèi)部異常:

executor.submit(() -> {
    try {
        throw new RuntimeException("任務(wù)異常");
    } catch (Exception e) {
        System.err.println("捕獲異常:" + e.getMessage());
    }
});

自定義線程工廠:

ThreadFactory factory = r -> {
    Thread t = new Thread(r);
    t.setUncaughtExceptionHandler((thread, e) -> {
        System.err.println("線程異常:" + e.getMessage());
    });
    return t;
};

7. 阻塞任務(wù)占用線程池

如果線程池中的任務(wù)是阻塞的(如文件讀寫、網(wǎng)絡(luò)請(qǐng)求),核心線程會(huì)被占滿,影響性能。

示例:阻塞任務(wù)拖垮線程池

executor.submit(() -> {
    Thread.sleep(10000); // 模擬阻塞任務(wù)
});

改進(jìn)方法

  • 減少任務(wù)的阻塞時(shí)間。
  • 增加核心線程數(shù)。
  • 使用異步非阻塞方式(如 NIO)。

8. 濫用線程池

線程池不是萬(wàn)能的,某些場(chǎng)景直接使用 new Thread() 更簡(jiǎn)單。

示例:過度使用線程池

一個(gè)簡(jiǎn)單的短期任務(wù):

ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(() -> System.out.println("執(zhí)行任務(wù)"));
executor.shutdown();

這種情況下,用線程池反而復(fù)雜。

改進(jìn)方式

new Thread(() -> System.out.println("執(zhí)行任務(wù)")).start();

9. 未監(jiān)控線程池狀態(tài)

很多人用線程池后,不監(jiān)控其狀態(tài),導(dǎo)致任務(wù)堆積、線程耗盡的問題被忽略。

示例:監(jiān)控線程池狀態(tài)

System.out.println("核心線程數(shù):" + executor.getCorePoolSize());
System.out.println("隊(duì)列大?。? + executor.getQueue().size());
System.out.println("已完成任務(wù)數(shù):" + executor.getCompletedTaskCount());

結(jié)合監(jiān)控工具(如 JMX、Prometheus),實(shí)現(xiàn)實(shí)時(shí)監(jiān)控。

10. 動(dòng)態(tài)調(diào)整線程池參數(shù)

有些人在線程池設(shè)計(jì)時(shí)忽略了參數(shù)調(diào)整的必要性,導(dǎo)致后期性能優(yōu)化困難。

示例:動(dòng)態(tài)調(diào)整核心線程數(shù)

executor.setCorePoolSize(20);
executor.setMaximumPoolSize(50);

實(shí)時(shí)調(diào)整線程池參數(shù),能適應(yīng)業(yè)務(wù)的動(dòng)態(tài)變化。

總結(jié)

線程池是強(qiáng)大的工具,但如果我們?nèi)粘9ぷ髦杏玫貌缓靡卜浅H菀撞瓤印?/p>

這篇文章通過實(shí)際代碼示例,我們可以清楚看到線程池的問題所在及改進(jìn)方法。

希望這些內(nèi)容能幫你避免踩坑,寫出高質(zhì)量的線程池代碼!

線程池用得好,效率杠杠的;用得不好,程序天天崩!

責(zé)任編輯:武曉燕 來源: 蘇三說技術(shù)
相關(guān)推薦

2022-08-16 08:27:20

線程毀線程異步

2015-03-24 16:29:55

默認(rèn)線程池java

2024-02-04 08:26:38

線程池參數(shù)內(nèi)存

2024-08-13 08:48:50

2024-08-26 08:29:55

2023-05-19 08:01:24

Key消費(fèi)場(chǎng)景

2024-07-15 08:20:24

2012-05-15 02:18:31

Java線程池

2020-12-10 08:24:40

線程池線程方法

2023-10-13 08:20:02

Spring線程池id

2023-02-24 14:46:32

Java線程池編程

2025-01-09 11:24:59

線程池美團(tuán)動(dòng)態(tài)配置中心

2023-06-07 13:49:00

多線程編程C#

2017-01-10 13:39:57

Python線程池進(jìn)程池

2019-12-27 09:09:42

Tomcat線程池JDK

2024-06-04 07:52:04

2020-06-04 12:15:37

Go內(nèi)存池對(duì)象池

2024-06-13 00:54:19

2024-03-28 12:51:00

Spring異步多線程

2010-03-15 17:17:29

Java線程池
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)