日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

阿里規范竟然不讓我用這種方式創建線程池

來源: 責編: 時間:2023-10-06 19:21:33 298觀看
導讀今天我們來聊一下這個 Java 中的線程池,線程池,這塊的內容,已經是非常的容易被面試官問到的內容,為什么呢?這是因為線程池,是一種多線程的處理方式,如果使用方式得當的話,那么對我們的代碼的質量也是非常高的。我們既然要了解

今天我們來聊一下這個 Java 中的線程池,線程池,這塊的內容,已經是非常的容易被面試官問到的內容,為什么呢?這是因為線程池,是一種多線程的處理方式,如果使用方式得當的話,那么對我們的代碼的質量也是非常高的。2d728資訊網——每日最新資訊28at.com

我們既然要了解線程池,那么肯定是需要從幾個角度來考慮,第一,什么是線程池?第二:為什么需要線程池?第三,線程池的創建方式都有哪些。2d728資訊網——每日最新資訊28at.com

什么是線程池

線程池是一種多線程處理形式,處理過程中將任務添加到隊列,然后在創建線程后自動啟動這些任務。2d728資訊網——每日最新資訊28at.com

線程池線程都是后臺線程。每個線程都使用默認的堆棧大小,以默認的優先級運行,并處于多線程單元 中。如果某個線程在托管代碼中空閑(如正在等待某個事件),則線程池將插入另一個輔助線程來使所 有處理器保持繁忙。2d728資訊網——每日最新資訊28at.com

如果所有線程池線程都始終保持繁忙,但隊列中包含掛起的工作,則線程池將在一段時間后創建另一個輔助線程但線程的數目永遠不會超過最大值。超過最大值的線程可以排隊,但他們要等到其他線程完成后才啟動。2d728資訊網——每日最新資訊28at.com

為什么需要線程池

我們有兩種常見的創建線程的方法,2d728資訊網——每日最新資訊28at.com

  • 一種是繼承Thread類,
  • 一種是實現Runnable的接口,Thread類其實也是實現了Runnable接口。

但是我們創建這兩種線程在運行結束后都會被虛擬機銷毀,如果線程數量多的話,頻繁的創建和銷毀線程會大大浪費時間和效率,更重要的是浪費內存。那么有沒有一種方法能讓線程運行完后不立即銷毀,而是讓線程重復使用,繼續執行其他的任務哪?2d728資訊網——每日最新資訊28at.com

這就是線程池的由來,很好的解決線程的重復利用,避免重復開銷。2d728資訊網——每日最新資訊28at.com

線程池的優點都有哪些?

(1)重用存在的線程,減少對象創建銷毀的開銷。2d728資訊網——每日最新資訊28at.com

(2)可有效的控制最大并發線程數,提高系統資源的使用率,同時避免過多資源競爭,避免堵塞。2d728資訊網——每日最新資訊28at.com

(3)提供定時執行、定期執行、單線程、并發數控制等功能。2d728資訊網——每日最新資訊28at.com

而且優點這么多,那么肯定就得知道 Java 提供了哪些線程池的實現方式了。2d728資訊網——每日最新資訊28at.com

Java 提供了哪幾種線程池

種類一

FixedThreadPool2d728資訊網——每日最新資訊28at.com

public static ExecutorService newFixedThreadPool(int nThreads) {        return new ThreadPoolExecutor(nThreads, nThreads,                                      0L, TimeUnit.MILLISECONDS,                                      new LinkedBlockingQueue<Runnable>());    }

newFixedThreadPool 實際上返回的是 ThreadPoolExecutor,ThreadPoolExecutor 實際就是線程池實現類,使用了典型的模板方法設計模式,通過ThreadPoolExecutor構造器的說明我們稍微解釋一下各參數的意思:2d728資訊網——每日最新資訊28at.com

構造器如下:2d728資訊網——每日最新資訊28at.com

public ThreadPoolExecutor(int corePoolSize,                              int maximumPoolSize,                              long keepAliveTime,                              TimeUnit unit,                              BlockingQueue<Runnable> workQueue) {        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,             Executors.defaultThreadFactory(), defaultHandler);    }
  • corePoolSize 核心線程數,線程池一直存在的線程(即使這些線程是空閑的),除非你設置allowCoreThreadTimeOut
  • maximumPoolSize 線程池中允許存在的最多的線程數,當workQueue滿了之后會創建線程直到數量達到maximumPoolSize
  • keepAliveTime 當線程池中的線程數超過核心線程數,超過部分的線程可以空閑keepAliveTime時間,如果這段時間還沒有任務過來則超過部分線程就會銷毀
  • unit keepAliveTime的單位
  • workQueue 等待隊列,當corePoolSize線程都在處理任務時,新進入線程池的任務則翻入等待下隊列
  • threadFactory 創建線程池中線程的線程工廠
  • handler 拒絕策略 當線程池已達到最大線程數和等待隊列也已經滿了,則使用拒絕策略

而newFixedThreadPool使用了corePoolSize和maximumPoolSize相等,所以當線程池線程數到達corePoolSize之后就不會再創建線程。2d728資訊網——每日最新資訊28at.com

并且newFixedThreadPool使用了LinkedBlockingQueue,而且使用的是默認構造器,容量是Integer.MAX_VALUE,keepAliveTime是0,實際上設不設置都沒關系,因為不會超過核心線程數。2d728資訊網——每日最新資訊28at.com

實際上我們也可以理解為FixedThreadPool該線程池中的線程數量始不變。當有一個新的任務提交時,線程池中若有空閑線程,則立即執行。若沒有,則新的任務會被暫存在一個任務隊列中,待有線程空閑時,便處理在任務隊列中的任務。2d728資訊網——每日最新資訊28at.com

種類二

SingleThreadExecutor2d728資訊網——每日最新資訊28at.com

實際上SingleThreadExecutor是使用單個 worker 線程的Executor。2d728資訊網——每日最新資訊28at.com

也就是說方法返回一個只有一個線程的線程池。若多余一個任務被提交到該線程 池,任務會被保存在一個任務隊列中,待線程空閑,按先入先出的順序執行隊列中的任務2d728資訊網——每日最新資訊28at.com

public static ExecutorService newSingleThreadExecutor() {        return new FinalizableDelegatedExecutorService            (new ThreadPoolExecutor(1, 1,                                    0L, TimeUnit.MILLISECONDS,                                    new LinkedBlockingQueue<Runnable>()));    }

SingleThreadExecutor 的 corePoolSize 和 maximumPoolSize 被設置為 1 。其他參數與 FixedThreadPool 相同。 SingleThreadExecutor 使用無 隊列 LinkedBlockingQueue 作 為線程池的工作隊列( 隊列的容量為Integer.MAX_VALUE )。2d728資訊網——每日最新資訊28at.com

種類三

CachedThreadPool2d728資訊網——每日最新資訊28at.com

該方法返回一個可根據實際情況調整線程數量的線程池。線程池的線程數 量不確定,但若有空閑線程可以復用,則會優先使用可復用的線程。若所有線程均在工作,又有新 的任務提交,則會創建新的線程處理任務。所有線程在當前任務執行完畢后,將返回線程池進行復 用。2d728資訊網——每日最新資訊28at.com

public static ExecutorService newCachedThreadPool() {        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,                                      60L, TimeUnit.SECONDS,                                      new SynchronousQueue<Runnable>());    }
  • 這個線程池corePoolSize是0,maximumPoolSize是Integer.MAX_VALUE,根據我們之前對源碼的分析,CachedThreadPool不會有核心線程,核心線程數的addworker方法不會執行,直接嘗試加入queue中。
  • keepAliveTime是60s,也就是60s從隊列中沒有拿到任務,worker就會自動銷毀。
  • queue使用的是SynchronousQueue,這個就是CachedThreadPool實現不停創建工作線程的關鍵,因為線程池處理任務分為三步:有任務過來先創建核心線程,當線程數達到核心線程數時則會進入等待隊列,當等待隊列滿了則再創建非核心線程,直到線程數達到最大線程數后執行拒絕策略,所以可以猜測SynchronousQueue應該是沒有容量的隊列,放入一個offer操作必須有一個poll操作在等待,沒有的話就執行入隊失敗,然后創建非核心線程進行處理
  • 線程工廠和拒絕策略都沒有指定,則使用的就是默認的,默認的拒絕策略是丟出一個異常

種類四

ScheduledThreadPoolExecutor2d728資訊網——每日最新資訊28at.com

這個線程池的構造器就比較多了2d728資訊網——每日最新資訊28at.com

// 第一個構造函數   public ScheduledThreadPoolExecutor(int corePoolSize) {       super(corePoolSize, Integer.MAX_VALUE,             DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,             new DelayedWorkQueue());   }   // 第二個構造函數   public ScheduledThreadPoolExecutor(int corePoolSize,                                      ThreadFactory threadFactory) {       super(corePoolSize, Integer.MAX_VALUE,             DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,             new DelayedWorkQueue(), threadFactory);   }   // 第三個構造函數   public ScheduledThreadPoolExecutor(int corePoolSize,                                      RejectedExecutionHandler handler) {       super(corePoolSize, Integer.MAX_VALUE,             DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,             new DelayedWorkQueue(), handler);   }   // 第四個構造函數   public ScheduledThreadPoolExecutor(int corePoolSize,                                      ThreadFactory threadFactory,                                      RejectedExecutionHandler handler) {       super(corePoolSize, Integer.MAX_VALUE,             DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,             new DelayedWorkQueue(), threadFactory, handler);   }

主要用來在給定的延遲后運行任務,或者定期執行任務。ScheduledThreadPoolExecutor又分為:ScheduledThreadPoolExecutor(包含多個線程)和SingleThreadScheduledExecutor (只包含一個線程)兩種。2d728資訊網——每日最新資訊28at.com

線程池的創建方式

其實創建方式,就是Executors,使用 Executors 可以非常輕易的創建我們上面所說的這幾種線程池。但是呢,有一個地方不知道大家有沒有注意到,在 阿里的開發手冊上面,是不允許使用 Executors 去創建的,更推薦我們使用的是 ThreadPoolExecutor 構造去創建,這樣的好處就是為了規避資源耗盡的風險那時候拋出的就不是異常,而是錯誤了。2d728資訊網——每日最新資訊28at.com

使用ThreadPoolExecutor的構造函數創建

private static ExecutorService executor = new ThreadPoolExecutor(13, 13,60L, TimeUnit.SECONDS,new ArrayBlockingQueue(13));

我們可以自己直接調用 ThreadPoolExecutor 的構造函數來自己創建線程池。在創建的同時,給 BlockQueue 指定容量就可以了。2d728資訊網——每日最新資訊28at.com

這時候如果提交的線程數超過了可用線程數的時候,就會拋出異常,比如 java.util.concurrent.RejectedExecutionException,這是因為當前線程池使用的隊列是有邊界隊列,隊列已經滿了便無法繼續處理新的請求。2d728資訊網——每日最新資訊28at.com

如果你覺得對 Error 和 Exception 沒有任何感覺得話,你也是可以使用 Executors 去創建的。2d728資訊網——每日最新資訊28at.com

你還知道有其他方式去創建線程池的么?2d728資訊網——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-12172-0.html阿里規范竟然不讓我用這種方式創建線程池

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 我們一起聊一聊Not only Java

下一篇: Python 中的真與假

標簽:
  • 熱門焦點
Top 主站蜘蛛池模板: 烟台市| 高邮市| 阜宁县| 曲水县| 南阳市| 昌宁县| 子洲县| 凤山市| 扶绥县| 庆城县| 锦州市| 盐边县| 综艺| 唐海县| 类乌齐县| 罗山县| 科技| 南召县| 七台河市| 张掖市| 巴林右旗| 昭平县| 锡林郭勒盟| 广昌县| 自贡市| 毕节市| 祁阳县| 炉霍县| 治县。| 南江县| 庆云县| 永善县| 如皋市| 昆山市| 洮南市| 茌平县| 隆尧县| 涞源县| 天长市| 安图县| 扬州市|