當前位置:首頁 » 編程語言 » java四種線程池

java四種線程池

發布時間: 2024-09-23 04:13:49

A. 深入理解java線程

深入理解Java線程進程和線程

進程

管道以及有名管道

信號

信號量

消息隊列

共享內存,比如實現分布式鎖

套接字

進程是操作系統資源分配的最小單位

問題: 進程之間是如何通信的,有哪些方式

線程

線程同步: 線程之間存在一種關系,一個線程需要等待另外一個線程的消息之後才能進行,否則就需要等待

線程互斥: 對於共享資源只能線程獨享,想要獲取需要等待另外一個線程釋放資源

volatile保證線程之間共享變數的可見性

管道輸入輸出流: PipedWriter、PIpedReader

join: 基於等待喚醒機制

線程是操作系統線程調度和執行的最小單位,而線程歸屬於進程

問題 Java線程之間如何通信的,有哪些方式

問題: 線程的同步和互斥

問題: 線程和進程之間的區別

線程更輕量級,線程的上下文切換成本比進程上下文切換成本低

進程間的通信比較復雜,線程之間的通信比較簡單比如共享進程內的內存

進程是操作系統資源分配的最小單位,線程是操作系統線程調度和執行的最小單位,而線程歸屬於進程

問題: 四種線程同步互斥的控制方法

臨界區: 通過對多線程的串列化來訪問公共資源或一段代碼,速度快,適合控制數據訪問(在一段時間內只允許一個線程訪問的資源就稱為臨界資源)

互斥量: 為協調共同對一個共享資源的單獨訪問而設計的

信號量: 為控制一個具有有限數量用戶資源而設計

事件: 用來通知線程有一些事件已發生,從而啟動後繼任務的開始

上下文切換

問題: 什麼是上下文切換

上下文切換是指CPU從一個進程或線程切換到另外一個線程或者進程,上下文切換會保存上一次的狀態,以便於下一次繼續執行

上下文切換只發生在內核態

上下文切換耗費時間成本比較大,盡量避免

問題: 上下文切換的步驟

暫停當前線程的處理,將當前線程的上下文保存下來,執行下一個線程的處理直到時間片用完暫停,再通過之前保存的上下文去繼續執行之前線程的處理

問題: 造成CPU上下文切換的方式

進程和線程的切換

系統調用

中斷機制

內核模式和用戶模式

問題: 什麼是內核模式和用戶模式

在用戶態,執行代碼不能直接訪問底層硬體,需要通過系統調用

在內核態,執行代碼可以完全不受限制的訪問底層硬體

內核模式(內核態)

用戶模式(用戶態)

問題: CAS操作是否涉及到用戶態到內核態的切換

CAS不會涉及到用戶態到內核態的切換,CAS在多核處理器下相當於在代碼里插入了lock cmpxchgl指令來保證原子性,而且執行指令比上下文切換開銷小,所以CAS比互斥鎖性能更高

操作系統層面線程的生命周期

操作系統層面線程的生命周期

線程一開始被創建時進入初始狀態,然後可以被分配給CPU時處於就緒狀態,當CPU空閑的時會從就緒狀態的線程中挑選一個線程去執行進入運行狀態,當運行狀態下的線程調用阻塞API時會進入阻塞狀態等待被喚醒繼續運行,當線程執行完或被異常停止處於終止狀態

初始狀態: 線程已經被創建,但是還不允許CPU執行

就緒狀態: 線程可以分配給CPU執行

運行狀態: 當CPU空閑的時候,會將它分配到一個就緒狀態的線程去使用

休眠狀態: 運行狀態的線程調用阻塞的API時會進入阻塞狀態等待被喚醒繼續運行

終止狀態: 線程執行結束或遇到異常

小結

Java層面線程的生命周期

Java層面線程的生命周期

NEW(初始化狀態)

RUNNABLE(就緒狀態 + 運行狀態 = 可運行狀態)

BLOCKED(阻塞狀態): 只有synchronized使用

TIMED_WAITING(有時限等待狀態): 調用wait()方法時指定等待的時長就會處於此狀態

TERMINATED(終止狀態)

問題: 概括的解釋下線程的幾種狀態

阻塞狀態就是指線程因為某種原因放棄了cpu使用權,也就是讓出了cpu時間片,暫時停止運行,直到線程進入可運行狀態,才有機會獲得cpu時間片轉到運行狀態

阻塞的情況分三種

死亡(dead): 線程run、main方法執行結束、異常退出run,就代表該線程生命周期結束,死亡的線程不可再次復生

等待阻塞: 運行的線程執行wait方法,JVM會把線程放入等待隊列中

同步阻塞: 運行線程在獲取對象的同步鎖的時候,如果鎖沒被釋放,JVM會把該線程放入鎖池中

其他阻塞: 運行的線程執行sleep、join、發送IO請求時,JVM會把線程變為阻塞狀態,當sleep超時、join等待線程終止或超時、IO處理完畢時,線程重新轉成可運行狀態

可運行狀態的線程獲得了cpu時間片,執行程序代碼

線程對象創建後,其他線程比如main線程調用了該對象的start方法,該狀態的線程位於可運行線程池中,等待被線程調度選中,獲取CPU的使用權

新創建一個線程對象

新建(new)

可運行(runnable)

運行(running)

阻塞(block)

Java線程Java線程概述

Java線程屬於內核級線程,是依賴於內核的也就是無論是用戶進程中的線程還是系統進程中的線程,它們的創建、撤銷、切換都是需要切換到內核態去執行

問題: ?為什麼說創建Java線程的方式本質只有一種

繼承Thread類實現run方法

實現Runable介面,實現run方法

實現Callable介面,實現call方法

通過線程池去創建線程: 推薦使用

雖然說創建線程的方式有以下幾種

但是本質只有一種,都是通過new Thread創建線程,調用Thread.start啟動線程,最終都會去調用Threead.run

問題: Java線程和Go的協程有什麼區別

協程是基於線程之上但是又更加輕量級的存在,協程存在於用戶態,不被操作系統內核管理

什麼是協程

如果線程不用切換到內核態,開銷非常小,就可以創建多個用戶級別來執行任務,這樣並發量特別高,所以Go天生就是和做這種大量並發的場景

問題: Java線程執行為什麼不能直接調用run方法,而要調用start方法

因為run方法並不是真正的線程,只是普通對象的方法,而start方法會通過操作系統去創建線程需要切換到內核態,Java線程的創建和銷毀是個比較重的操作,因為涉及到內核態切換,所以我們一般不會每一個任務分配一個線程而是選擇線程復用的方式比如使用線程池

Thread的常用方法

sleep

調用sleep會讓當前線程從RUNNING進入TIMED_WAITING,不會釋放對象鎖

其他線程可以通過interrupt方法打斷正在睡眠的線程,sleep方法會拋出終端異常並且清除中斷標志

睡眠結束後的線程未必立刻得到執行

sleep傳入參數為0時和yield相同

yield

yield會釋放CPU資源,讓當前線程從RUNNING進入RUNNABLE狀態,讓優先順序更高的線程獲得執行機會,不會釋放對象鎖

假設當前進程只有main線程,當調用yield之後,main線程會繼續運行,因為沒有比它優先順序更高的線程

具體的實現依賴於操作系統的任務調度

join

可以理解為線程合並,當在一個線程調用另外一個線程的join時,當前線程阻塞等待被調用join的線程執行完畢才能繼續執行,所以join的好處就是能夠保證線程的執行順序,但如果調用線程的join方法其實已經失去了並行的意義,雖然存在多個線程,但本質上是串列的,最後join底層也是採用等待喚醒機制

等待調用join方法的線程結束之後,程序再繼續執行,一般用於等待非同步線程執行完結果之後才能繼續運行的場景

注意

stop

stop方法會釋放對象鎖,可能會造成數據不一致,因為stop方法太暴力,會強行把執行到一半的線程終止

Java線程的實現原理

線程創建和啟動流程

使用new Thread()創建一個線程,然後調用start()方法進行java層面線程啟動

使用本地方法start0(),去調用JVM中的JVM_StartThread()方法創建和啟動

調用new JavaThread(&thread_entry,sz)進行線程的創建,並根據不同的操作系統平台調用對應os::create_thread()方法進行線程創建

新創建的線程狀態是initialized,調用了sync->wait()的方法進行等待,等到被喚醒才繼續執行thread->run()

調用Thread.start(native_thread)方法進行線程啟動,此時將線程狀態設置為RUNNABLE,接著調用os::start_thread(thread),根據不同的操作系統選擇不同的線程啟動方式

線程啟動之後狀態設置為RUNNABLE,並且喚醒第四步中等待的線程,接著執行thread->run()方法

JavaThread::run()方法會回調第一步的new Thread()中復寫的run()方法

Java線程的調度機制

協同式線程調度: 線程執行時間由線程本身控制,但缺點是線程執行時間不可控制,如果一個線程有問題,可能一直阻塞在那

搶占式線程調度: 無法控制CPU時間片在哪停止,且線程的切換不由線程本身決定,Java默認就是搶占度調度

注意

輪循調度優點是簡潔性,它無序記錄當前所有連接的狀態,所以它是一種無狀態調度

搶占式調度實現相對復雜

Java線程的中斷機制

Java沒有提供一種安全、直接的方法來停止某個線程,而是提供了中斷機制

中斷機制是一種協作機制,也就是說通過中斷並不能直接終止另一個線程,而需要被中斷的線程自己處理

被中斷的線程擁有完全的自主權,它既可以選擇立即停止,也可以選擇一段時間後停止,也可以選擇壓根不停止

API的使用

interrupt(): 將線程的中斷標志位設置為true,不會停止線程

isInterrupted(): 判斷當前線程的中斷標志位是否為true,不會清除中斷標志位

Thread.interrupted():判斷當前線程的中斷標志位是否為true,並清除中斷標志位,重置為fasle

問題: 如何優雅的終止線程

stop會釋放鎖,強制終止線程,不推薦使用

可以通過while配合isInterrupted方法以及對應的結束標記來使用,注意如果代碼塊中有調用清除中斷標記為的API時,如果使用了sleep、wait記得手動添加標記位

等待喚醒機制

等待喚醒機制可以基於wait和notify方法來實現,在一個線程內調用該線程鎖對象的wait方法,線程將進入等待隊列進行等待直到被喚醒

Monitor機制去提供,只作用於synchronized同步塊,而且無法喚醒指定線程,而unpark可以指定線程,notify不可提前調用

notify()是隨機性的,只隨機喚醒一個 wait 線程

notifyAll()會喚醒所有wait線程

一般使用這種,可以喚醒指定線程,unpark提前去掉也是可以的

park/unpark

wait/notify/notifyAll

協程

協程是一種基於線程之上,但又比線程更加輕量級的存在,協程不是被操作系統內核所管理,而完全是由程序所控制(也就是在用戶態執行),具有對內核來說不可見的特性。這樣帶來的好處就是性能得到了很大的提升

問題: 協程的特點在於是一個線程執行,那和多線程比,協程有何優勢

線程的切換由操作系統調度,協程由用戶自己進行調度,因此減少了上下文切換,提高了效率

線程是默認stack大小是1M,而協程更輕量,接近1k.因此可以在相同的內存中開啟更多的協程

不需要多線程的鎖機制,因為只有一個線程,也不存在同時寫變數沖突,在協程中控制共享資源不加鎖,只需要判斷狀態就好了,所以執行效率比多線程高很多

問題: Java中是否存在協程

kilim ?quasar框架

注意

協程適用於被阻塞的,且需要大量並發的場景(網路io)

不適合大量計算的場景

原文:https://juejin.cn/post/7100994816468582407

B. 已拿32k小米Android高級開發offer(面試題回顧)

到現在我入職也有一段時間了,這才有空梳理一下當時的面試題。簡單說下我的情況:這是一次比較平常的跳槽,不是什麼逆襲大廠的劇本,只是薪資有所漲幅。

個人經歷不詳說,面試題對大家來說可能更有參考性,本篇先整理小米的面試題,我前後也面了很多個大廠,有空把其他幾個大廠的面試題也總結一下。

Java基礎肯定是少不了要問的,這輪面試Kotlin相對來說是我這些面試中問得比較多的,所以說准備面試還是要面面俱到。

我有點佩服我的記憶力了。這部分涉及到更多的 源碼、原理和優化 方面的問題,Android高級開發需要具備一些什麼能力大家也應該有所衡量了。

最後給大家分享一份 2246頁 Android大廠高頻面試題解析大全 ,基本上把我的面試內容都涵蓋到了: Android、性能優化、Java、Kotlin、網路、插件化、熱修復、模塊化、組件化、增量更新、Gradle、圖片、Flutter等。

這份資料免費提供給大家復習,文末查看領取方式,搞定Android面試這一份肯定夠了。

第一章 Android相關 (源碼分析、性能優化、Framework等)

第二章 性能優化 (GC原理、布局優化、繪制優化、內存優化等)

第三章 Java相關 (四種線程池、JVM、內存管理、垃圾回收、引用等)

第四章 Kotlin相關 (延遲初始化、Reified、Extension Functions、函數等)

第五章 網路相關 (HTTP 知識體系、HttpDns 原理、TCP,UDP,HTTP,SOCKET 之間的區別等)

第六章 插件化&熱修復&模塊化&組件化&增量更新&Gradle

第七章 圖片相關 (圖片庫對比、LRUCache原理、圖片載入原理、Glide等)

第八章 Flutter相關 (Flutter原理、Flutter Hot Reload、Flutter 動態化 探索 、Flutter Platform Channel等)

需要這份資料的朋友私信我【面試題】就可以免費領取。

希望大家都可以把握住每一次自我提升的機會,把每一步都走踏實了,漲薪升職什麼的都會迎你而來。

也歡迎大家和我一起交流Android方面的事情。

C. java 線程池ThreadPoolExecutor 共同完成一個任務

線程池可以解決兩個不同問題:由於減少了每個任務調用的開銷,它們通常可以在執行大量非同步任務時提供增強的性能,並且還可以提供綁定和管理資源(包括執行集合任務時使用的線程)的方法。每個ThreadPoolExecutor 還維護著一些基本的統計數據,如完成的任務數。

為了便於跨大量上下文使用,此類提供了很多可調整的參數和擴展掛鉤。但是,強烈建議程序員使用較為方便的 Executors 工廠方法 Executors.newCachedThreadPool()(無界線程池,可以進行自動線程回收)、Executors.newFixedThreadPool(int)(固定大小線程池)和 Executors.newSingleThreadExecutor()(單個後台線程),它們均為大多數使用場景預定義了設置。否則,在手動配置和調整此類時,使用以下指導:

核心和最大池大小
ThreadPoolExecutor 將根據 corePoolSize(參見 getCorePoolSize())和 maximumPoolSize(參見getMaximumPoolSize())設置的邊界自動調整池大小。當新任務在方法 execute(java.lang.Runnable) 中提交時,如果運行的線程少於 corePoolSize,則創建新線程來處理請求,即使其他輔助線程是空閑的。如果運行的線程多於corePoolSize 而少於 maximumPoolSize,則僅當隊列滿時才創建新線程。如果設置的 corePoolSize 和 maximumPoolSize相同,則創建了固定大小的線程池。如果將 maximumPoolSize 設置為基本的無界值(如 Integer.MAX_VALUE),則允許池適應任意數量的並發任務。在大多數情況下,核心和最大池大小僅基於構造來設置,不過也可以使用setCorePoolSize(int) 和 setMaximumPoolSize(int) 進行動態更改。

按需構造
默認情況下,即使核心線程最初只是在新任務需要時才創建和啟動的,也可以使用方法 prestartCoreThread()或 prestartAllCoreThreads() 對其進行動態重寫。

創建新線程
使用 ThreadFactory 創建新線程。如果沒有另外說明,則在同一個 ThreadGroup 中一律使用Executors.defaultThreadFactory() 創建線程,並且這些線程具有相同的 NORM_PRIORITY 優先順序和非守護進程狀態。通過提供不同的 ThreadFactory,可以改變線程的名稱、線程組、優先順序、守護進程狀態,等等。如果從 newThread返回 null 時 ThreadFactory 未能創建線程,則執行程序將繼續運行,但不能執行任何任務。
保持活動時間
如果池中當前有多於 corePoolSize 的線程,則這些多出的線程在空閑時間超過 keepAliveTime 時將會終止(參見getKeepAliveTime(java.util.concurrent.TimeUnit))。這提供了當池處於非活動狀態時減少資源消耗的方法。如果池後來變得更為活動,則可以創建新的線程。也可以使用方法 setKeepAliveTime(long, java.util.concurrent.TimeUnit) 動態地更改此參數。使用 Long.MAX_VALUE TimeUnit.NANOSECONDS 的值在關閉前有效地從以前的終止狀態禁用空閑線程。

排隊
所有 BlockingQueue 都可用於傳輸和保持提交的任務。可以使用此隊列與池大小進行交互:
A. 如果運行的線程少於 corePoolSize,則 Executor 始終首選添加新的線程,而不進行排隊。
B. 如果運行的線程等於或多於 corePoolSize,則 Executor 始終首選將請求加入隊列,而不添加新的線程。
C. 如果無法將請求加入隊列,則創建新的線程,除非創建此線程超出 maximumPoolSize,在這種情況下,任務將被拒絕。

排隊有三種通用策略:
直接提交。工作隊列的默認選項是 SynchronousQueue,它將任務直接提交給線程而不保持它們。在此,如果不存在可用於立即運行任務的線程,則試圖把任務加入隊列將失敗,因此會構造一個新的線程。此策略可以避免在處理可能具有內部依賴性的請求集合時出現鎖定。直接提交通常要求無界 maximumPoolSizes 以避免拒絕新提交的任務。當命令以超過隊列所能處理的平均數連續到達時,此策略允許無界線程具有增長的可能性。
無界隊列。使用無界隊列(例如,不具有預定義容量的 LinkedBlockingQueue)將導致在所有 corePoolSize 線程都忙的情況下將新任務加入隊列。這樣,創建的線程就不會超過 corePoolSize。(因此,maximumPoolSize 的值也就無效了。)當每個任務完全獨立於其他任務,即任務執行互不影響時,適合於使用無界隊列;例如,在 Web 頁伺服器中。這種排隊可用於處理瞬態突發請求,當命令以超過隊列所能處理的平均數連續到達時,此策略允許無界線程具有增長的可能性。
有界隊列。當使用有限的 maximumPoolSizes 時,有界隊列(如 ArrayBlockingQueue)有助於防止資源耗盡,但是可能較難調整和控制。隊列大小和最大池大小可能需要相互折衷:使用大型隊列和小型池可以最大限度地降低CPU 使用率、操作系統資源和上下文切換開銷,但是可能導致人工降低吞吐量。如果任務頻繁阻塞(例如,如果它們是 I/O 邊界),則系統可能為超過您許可的更多線程安排時間。使用小型隊列通常要求較大的池大小,CPU 使用率較高,但是可能遇到不可接受的調度開銷,這樣也會降低吞吐量。
被拒絕的任務

當 Executor 已經關閉,並且 Executor 將有限邊界用於最大線程和工作隊列容量,且已經飽和時,在方法execute(java.lang.Runnable) 中提交的新任務將被拒絕。在以上兩種情況下,execute 方法都將調用其RejectedExecutionHandler 的 RejectedExecutionHandler.rejectedExecution(java.lang.Runnable, java.util.concurrent.ThreadPoolExecutor) 方法。下面提供了四種預定義的處理程序策略:
A. 在默認的 ThreadPoolExecutor.AbortPolicy 中,處理程序遭到拒絕將拋出運行時 RejectedExecutionException。
B. 在 ThreadPoolExecutor.CallerRunsPolicy 中,線程調用運行該任務的 execute 本身。此策略提供簡單的反饋控制機制,能夠減緩新任務的提交速度。
C. 在 ThreadPoolExecutor.DiscardPolicy 中,不能執行的任務將被刪除。
D. 在 ThreadPoolExecutor.DiscardOldestPolicy 中,如果執行程序尚未關閉,則位於工作隊列頭部的任務將被刪除,然後重試執行程序(如果再次失敗,則重復此過程)。
定義和使用其他種類的 RejectedExecutionHandler 類也是可能的,但這樣做需要非常小心,尤其是當策略僅用於特定容量或排隊策略時。

掛鉤方法
此類提供 protected 可重寫的 beforeExecute(java.lang.Thread, java.lang.Runnable) 和 afterExecute(java.lang.Runnable, java.lang.Throwable) 方法,這兩種方法分別在執行每個任務之前和之後調用。它們可用於操縱執行環境;例如,重新初始化ThreadLocal、搜集統計信息或添加日誌條目。此外,還可以重寫方法 terminated() 來執行 Executor 完全終止後需要完成的所有特殊處理。

如果掛鉤或回調方法拋出異常,則內部輔助線程將依次失敗並突然終止。

隊列維護
方法 getQueue() 允許出於監控和調試目的而訪問工作隊列。強烈反對出於其他任何目的而使用此方法。remove(java.lang.Runnable) 和 purge() 這兩種方法可用於在取消大量已排隊任務時幫助進行存儲回收。

一、例子

創建 TestThreadPool 類:
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TestThreadPool {

private static int proceTaskSleepTime = 2;

private static int proceTaskMaxNumber = 10;

public static void main(String[] args) {

// 構造一個線程池
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 4, 3,
TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(3),
new ThreadPoolExecutor.DiscardOldestPolicy());

for (int i = 1; i <= proceTaskMaxNumber; i++) {
try {
String task = "task@ " + i;
System.out.println("創建任務並提交到線程池中:" + task);
threadPool.execute(new ThreadPoolTask(task));

Thread.sleep(proceTaskSleepTime);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
view plain
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TestThreadPool {

private static int proceTaskSleepTime = 2;

private static int proceTaskMaxNumber = 10;

public static void main(String[] args) {

// 構造一個線程池
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 4, 3,
TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(3),
new ThreadPoolExecutor.DiscardOldestPolicy());

for (int i = 1; i <= proceTaskMaxNumber; i++) {
try {
String task = "task@ " + i;
System.out.println("創建任務並提交到線程池中:" + task);
threadPool.execute(new ThreadPoolTask(task));

Thread.sleep(proceTaskSleepTime);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

創建 ThreadPoolTask類:
view plain to clipboardprint?
import java.io.Serializable;

public class ThreadPoolTask implements Runnable, Serializable {

private Object attachData;

ThreadPoolTask(Object tasks) {
this.attachData = tasks;
}

public void run() {

System.out.println("開始執行任務:" + attachData);

attachData = null;
}

public Object getTask() {
return this.attachData;
}
}
view plain
import java.io.Serializable;

public class ThreadPoolTask implements Runnable, Serializable {

private Object attachData;

ThreadPoolTask(Object tasks) {
this.attachData = tasks;
}

public void run() {

System.out.println("開始執行任務:" + attachData);

attachData = null;
}

public Object getTask() {
return this.attachData;
}
}

執行結果:
創建任務並提交到線程池中:task@ 1
開始執行任務:task@ 1
創建任務並提交到線程池中:task@ 2
開始執行任務:task@ 2
創建任務並提交到線程池中:task@ 3
創建任務並提交到線程池中:task@ 4
開始執行任務:task@ 3
創建任務並提交到線程池中:task@ 5
開始執行任務:task@ 4
創建任務並提交到線程池中:task@ 6
創建任務並提交到線程池中:task@ 7
創建任務並提交到線程池中:task@ 8
開始執行任務:task@ 5
開始執行任務:task@ 6
創建任務並提交到線程池中:task@ 9
開始執行任務:task@ 7
創建任務並提交到線程池中:task@ 10
開始執行任務:task@ 8
開始執行任務:task@ 9
開始執行任務:task@ 10

ThreadPoolExecutor配置
一、ThreadPoolExcutor為一些Executor提供了基本的實現,這些Executor是由Executors中的工廠 newCahceThreadPool、newFixedThreadPool和newScheledThreadExecutor返回的。 ThreadPoolExecutor是一個靈活的健壯的池實現,允許各種各樣的用戶定製。
二、線程的創建與銷毀
1、核心池大小、最大池大小和存活時間共同管理著線程的創建與銷毀。
2、核心池的大小是目標的大小;線程池的實現試圖維護池的大小;即使沒有任務執行,池的大小也等於核心池的大小,並直到工作隊列充滿前,池都不會創建更多的線程。如果當前池的大小超過了核心池的大小,線程池就會終止它。
3、最大池的大小是可同時活動的線程數的上限。
4、如果一個線程已經閑置的時間超過了存活時間,它將成為一個被回收的候選者。
5、newFixedThreadPool工廠為請求的池設置了核心池的大小和最大池的大小,而且池永遠不會超時
6、newCacheThreadPool工廠將最大池的大小設置為Integer.MAX_VALUE,核心池的大小設置為0,超時設置為一分鍾。這樣創建了無限擴大的線程池,會在需求量減少的情況下減少線程數量。
三、管理
1、 ThreadPoolExecutor允許你提供一個BlockingQueue來持有等待執行的任務。任務排隊有3種基本方法:無限隊列、有限隊列和同步移交。
2、 newFixedThreadPool和newSingleThreadExectuor默認使用的是一個無限的 LinkedBlockingQueue。如果所有的工作者線程都處於忙碌狀態,任務會在隊列中等候。如果任務持續快速到達,超過了它們被執行的速度,隊列也會無限制地增加。穩妥的策略是使用有限隊列,比如ArrayBlockingQueue或有限的LinkedBlockingQueue以及 PriorityBlockingQueue。
3、對於龐大或無限的池,可以使用SynchronousQueue,完全繞開隊列,直接將任務由生產者交給工作者線程
4、可以使用PriorityBlockingQueue通過優先順序安排任務

D. java多線程有幾種實現方法

  • 繼承Thread類來實現多線程:

  • 當我們自定義的類繼承Thread類後,該類就為一個線程類,該類為一個獨立的執行單元,線程代碼必須編寫在run()方法中,run方法是由Thread類定義,我們自己寫的線程類必須重寫run方法。

    run方法中定義的代碼為線程代碼,但run方法不能直接調用,如果直接調用並沒有開啟新的線程而是將run方法交給調用的線程執行

    要開啟新的線程需要調用Thread類的start()方法,該方法自動開啟一個新的線程並自動執行run方法中的內容


    *java多線程的啟動順序不一定是線程執行的順序,各個線程之間是搶佔CPU資源執行的,所有有可能出現與啟動順序不一致的情況。


    CPU的調用策略:

    如何使用CPU資源是由操作系統來決定的,但操作系統只能決定CPU的使用策略不能控制實際獲得CPU執行權的程序。


    線程執行有兩種方式:


    1.搶占式:

    目前PC機中使用最多的一種方式,線程搶佔CPU的執行權,當一個線程搶到CPU的資源後並不是一直執行到此線程執行結束,而是執行一個時間片後讓出CPU資源,此時同其他線程再次搶佔CPU資源獲得執行權。


    2.輪循式;

    每個線程執行固定的時間片後讓出CPU資源,以此循環執行每個線程執行相同的時間片後讓出CPU資源交給下一個線程執行。

熱點內容
上傳1080p視頻騰訊 發布:2024-09-23 06:36:24 瀏覽:925
光遇安卓國服是從什麼季節開始 發布:2024-09-23 06:34:56 瀏覽:487
安卓如何投屏賓士 發布:2024-09-23 06:25:25 瀏覽:463
win伺服器轉發ip 發布:2024-09-23 06:15:27 瀏覽:571
macbook照片怎麼放入安卓 發布:2024-09-23 06:03:08 瀏覽:406
關系型資料庫的原理 發布:2024-09-23 05:58:34 瀏覽:576
商城模板html源碼 發布:2024-09-23 05:58:31 瀏覽:342
我的世界最新好玩兒的伺服器 發布:2024-09-23 05:41:04 瀏覽:593
編譯時類型 發布:2024-09-23 05:39:30 瀏覽:317
腳本運行游戲卡頓 發布:2024-09-23 05:24:56 瀏覽:781