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
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...