JUC併發編程學習筆記(十)線程池(重點)

来源:https://www.cnblogs.com/nhgtx/archive/2023/11/04/17806011.html
-Advertisement-
Play Games

線程池(重點) 線程池:三大方法、七大參數、四種拒絕策略 池化技術 程式的運行,本質:占用系統的資源!優化資源的使用!-> 池化技術(線程池、連接池、對象池......);創建和銷毀十分消耗資源 池化技術:事先準備好一些資源,有人要用就拿,拿完用完還給我。 線程池的好處: 1、降低資源消耗 2、提高 ...


線程池(重點)

線程池:三大方法、七大參數、四種拒絕策略

池化技術

程式的運行,本質:占用系統的資源!優化資源的使用!-> 池化技術(線程池、連接池、對象池......);創建和銷毀十分消耗資源

池化技術:事先準備好一些資源,有人要用就拿,拿完用完還給我。

線程池的好處:

1、降低資源消耗

2、提高相應速度

3、方便管理

線程復用、可以控制最大併發數、管理線程

線程池:三大方法

1、newSingleThreadExecutor

單列線程池,只有一條線程;

單例線程池配合callable使用,註意需要在程式運行結束後關閉線程池

package org.example.pool;

import java.util.concurrent.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

//Executors->工具類
public class Demo01 {
    public static void main(String[] args) {
        TestCallable able = new TestCallable();

        //三大方法
        ExecutorService threadPool = Executors.newSingleThreadExecutor();//單個線程


        try {
            for (int i = 0; i < 10; i++) {
                FutureTask<String> task = new FutureTask<String>(able);

                //線程池創建線程
                threadPool.execute(task);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //線程池用完,程式結束,關閉線程池
            threadPool.shutdown();
        }


//        Executors.newFixedThreadPool(5);//固定線程池大小
//        Executors.newCachedThreadPool();//可伸縮的線程池
    }
}

class TestCallable implements Callable<String> {
    Lock lock = new ReentrantLock();

    @Override
    public String call() throws Exception {
        TimeUnit.SECONDS.sleep(2);
        System.out.println(Thread.currentThread().getName() + ":ok");
        return Thread.currentThread().getName() + ":ok";
    }
}

註意結果圖

在單例線程池中,運行結果發現都是同一條線程在操作資源,整個線程池中只有一條pool-1-thread-1線程。

2、newFixedThreadPool

同樣的代碼,將線程池切換為固定大小的線程池,設置為5條,這樣跑出來的結果又不一樣

由於設置了線程休眠,所以會導致比較平均的結果出現,但是一般情況下都是五條線程搶占資源,每次結果都是不一定的,看那條線程處理的比較快搶占的比較多。

3、newCachedThreadPool

同樣的代碼,將線程池切換為可伸縮大小的線程池,這樣跑出來的結果又不一樣

image-20231007193007427

根據業務代碼生成具體條數的線程:如本次業務通過迴圈或其他因數,同時需要處理10條任務,那麼當你線程池中的第一條線程還未完成任務時就會生成一條新的線程來同步處理這些任務,只要你cpu處理速度夠快那麼理論最高可能同時生成一個具有10條線程(任務數)的一個線程池。

七大參數

源碼分析

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newFixedThreadPool(int nThreads) {
    //和以上沒有區別,只是通過用戶調用來完成的,相當於new ThreadPoolExecutor(5, 5,....)
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool() {
    //設置了預設是0個線程,但是最大值可以達到大約21億條,設置了Integer.MAX_VALUE(約21億)
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,//如果通過Integer.MAX_VALUE來跑線程池一定會照成OOM(溢出)
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

通過觀察以上三大方法的創建線程池方式,可以發現,三大方法的本質都是調用ThreadPoolExecutor來創建的

public ThreadPoolExecutor(int corePoolSize,//核心線程池大小
                          int maximumPoolSize,//最大線程池大小
                          long keepAliveTime,//超時無調用釋放
                          TimeUnit unit,//超時單位
                          BlockingQueue<Runnable> workQueue,//阻塞隊列
                          ThreadFactory threadFactory,//線程工廠,創建線程的,一般不用動
                          RejectedExecutionHandler handler) {//拒絕策略
    if (corePoolSize < 0 ||
        maximumPoolSize <= 0 ||
        maximumPoolSize < corePoolSize ||
        keepAliveTime < 0)
        throw new IllegalArgumentException();
    if (workQueue == null || threadFactory == null || handler == null)
        throw new NullPointerException();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

這就是為什麼阿裡巴巴開發規範中說不要使用Executors來創建線程池而是讓我們通過ThreadPoolExecutor來創建,其實就是讓我們通過瞭解線程池的本質來避免一些問題。

模擬銀行業務模塊模擬

package org.example.pool;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Demo02 {
    public static void main(String[] args) {
        //自定義線程池,工作中只會使用ThreadPoolExecutor
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2,
                5,
                3,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(3),
                new ThreadPoolExecutor.AbortPolicy());//拒絕策略,即當阻塞隊列和線程池線程都已經最大化運行沒有任何位置可以處置接下來的元素了,就拒絕該元素進入並拋出異常
        try {
            //最大承載 隊列Queue+max
            for (int i = 0; i < 10; i++) {
                //線程池創建線程
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName() + ":ok");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //線程池用完,程式結束,關閉線程池
            threadPool.shutdown();
        }
    }
}

此時有10個任務,但是最大線程量只有5個,阻塞隊列量只有三個,所以註定會有兩個無法處理,此時觸發拒絕策略,拋出異常並且拒絕該任務。

可以看到執行了八個任務,通過五條不同的線程。執行了拒絕策略拋出了異常java.util.concurrent.RejectedExecutionException

四種拒絕策略

四種拒絕策略的描述

//AbortPolicy 隊列滿了,丟掉任務,拋出異常
//CallerRunsPolicy 哪條線程給的任務回到哪條線程去執行,線程池不執行
//DiscardPolicy 隊列滿了,丟掉任務,但不拋出異常
//DiscardOldestPolicy 隊列滿了,嘗試去和最早的競爭,如果沒成功,依舊丟棄任務,但不拋出異常

小結和拓展

瞭解:IO密集型、cpu密集型(調優)

/*
* 最大線程到底該如何定義
* 1、CPU 密集型,幾何就定義為幾,就可以保證cpu效率最高的
* 2、IO 密集型 > 判斷你程式中十分耗IO的線程,
* 程式    15個大小任務 io十分占用資源
* */

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Python 允許用戶輸入數據。這意味著我們可以向用戶詢問輸入。在 Python 3.6 中,使用 input() 方法來獲取用戶輸入。在 Python 2.7 中,使用 raw_input() 方法來獲取用戶輸入。以下示例要求用戶輸入用戶名,併在輸入用戶名後將其列印在屏幕上: Python 3.6 ...
  • OpenSSL 中的 `SSL` 加密是通過 `SSL/TLS` 協議來實現的。`SSL/TLS` 是一種安全通信協議,可以保障通信雙方之間的通信安全性和數據完整性。在 `SSL/TLS` 協議中,加密演算法是其中最核心的組成部分之一,SSL可以使用各類加密演算法進行密鑰協商,一般來說會使用`RSA`等... ...
  • 四大函數式介面(必備) 程式員:泛型、反射、註解、枚舉 新時代程式員:lambda表達式、鏈式編程、函數式介面、Stream流式計算 函數式介面:只有一個方法的介面 @FunctionalInterface public interface Runnable { public abstract vo ...
  • 推薦一個分散式圖資料庫Nebula Graph,萬億級數據,毫秒級延時 什麼是Nebula Graph Nebula Graph 是一款開源的、分散式的、易擴展的原生圖資料庫,能夠承載包含數千億個點和數萬億條邊的超大規模數據集,並且提供毫秒級查詢 什麼是圖資料庫 圖資料庫是專門存儲龐大的圖形網路並從 ...
  • 高精度的本質是將數字以字元串的形式讀入,然後將每一位分別存放入`int`數組中,通過模擬每一位的運算過程,來實現最終的運算效果。 ...
  • 對於手工計算來說,積分計算是非常困難的,對於一些簡單的函數,我們可以直接通過已知的積分公式來求解,但在更多的情況下,原函數並沒有簡單的表達式,因此確定積分的反函數變得非常困難。 另外,相對於微分運算來說,積分運算則具有更多的多樣性,包括不同的積分方法(如換元積分法、分部積分法等)和積分技巧,需要根據 ...
  • 一、概念 AOP面向切麵編程,一種編程範式 二、作用 在不改動原始設計(原代碼不改動)的基礎上為方法進行功能增強(即增加功能) 三、核心概念 1、代理(Proxy):SpringAOP的核心本質是採用代理模式實現的 2、連接點(JoinPoint):在SpringAOP中,理解為任意方法的執行 3、 ...
  • Go 方法集合與選擇receiver類型 目錄Go 方法集合與選擇receiver類型一、receiver 參數類型對 Go 方法的影響二、選擇 receiver 參數類型原則2.1 選擇 receiver 參數類型的第一個原則2.2 選擇 receiver 參數類型的第二個原則三、方法集合(Met ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...