基本概念。
程序:執行在作業系統上的程式,如QQ和IDE。
執行緒:乙個程序可以有多個執行緒,例如同時收聽聲音、影象和彈幕。
多執行緒:多個執行緒併發執行。
同步:通過人工控制和排程,保證對共享資源的多執行緒訪問是執行緒安全的,以保證結果的準確性,如同步關鍵字,在保證結果準確性的同時提高效能,執行緒安全優先順序高於效能。
並行性:多個 CPU 例項或多台機器同時執行一段處理邏輯。
併發性:通過CPU排程演算法,使用者看似同時執行,但實際上從CPU操作層面來看,其實並不是同時執行的。
執行緒的生命週期。
新狀態:當程式使用 new 關鍵字建立執行緒時,該執行緒處於新狀態,只有 JVM 為其分配記憶體並初始化其成員變數的值。
就緒狀態:當執行緒物件呼叫 start() 方法時,執行緒處於就緒狀態。 j**a 虛擬機器建立乙個方法呼叫堆疊和程式計數器,以便計畫執行。
執行狀態:如果處於就緒狀態的執行緒獲取 CPU 並開始執行 run() 方法,則該執行緒處於執行狀態。
阻塞狀態:當處於執行狀態的執行緒失去占用的資源時,進入阻塞狀態。
死態:執行緒在執行 run() 方法後進入死態。 此外,如果執行緒執行 interrupt() 或 stop() 方法,那麼它也會進入死狀態並異常退出。
執行緒池。 什麼是執行緒池?
乙個可以容納多個執行緒的容器,其中執行緒可以重複使用,無需頻繁建立執行緒物件,重複建立執行緒會消耗過多的系統資源。
為什麼要使用執行緒池?
建立執行緒的方法有兩種,一種是繼承執行緒類,另一種是實現 runnable 介面,實際上就是 runnable 介面。 但是,這兩個執行緒在執行結束時都會被 JVM 銷毀,如果執行緒很多,頻繁建立和銷毀執行緒會浪費記憶體。 那麼有沒有辦法讓執行緒在執行完後不立即被銷毀,而是讓執行緒復用並繼續執行其他任務呢?
這就是執行緒池的由來,是執行緒復用的好辦法,避免了重複開銷。
執行緒池任務執行過程。
執行緒池的優點。
1.執行緒是稀缺資源,使用執行緒池可以減少執行緒的建立和銷毀次數,並且每個工作執行緒都可以重複使用。
2、可根據系統容差調整執行緒池中的工作執行緒數,防止伺服器因記憶體消耗過大而崩潰。
執行緒池引數。
拒絕策略預定義有四種型別:
1)AbortPolicy(預設策略):當執行緒池的任務佇列已滿,執行緒池內所有執行緒都忙時,會直接拒絕新提交的任務,並丟擲rejectedexecution異常。
2)CallerRunsPolicy:當執行緒池的任務佇列已滿且執行緒池中的執行緒繁忙時,新提交的任務將由提交任務的執行緒所在的執行緒池執行。也就是說,當前執行緒將直接執行任務。
3)DiscardOldestPolicy:當執行緒池的任務佇列已滿且執行緒池中的執行緒繁忙時,將丟棄佇列中最早的任務,並嘗試將新提交的任務新增到佇列中。
4)DiscardPolicy:當執行緒池的任務佇列已滿且執行緒池中的執行緒繁忙時,不進行任何處理即可丟棄新提交的任務。
future
執行執行緒時可以有兩種形式,一種具有返回值,另一種沒有返回值。 當我們得到乙個正在執行的執行緒的返回值時,我們需要將其與 future 結合使用。
您可以使用 futures 將任務提交到執行緒池執行,並在需要時獲取任務的執行結果。 其主要目的是允許主線程在提交非同步任務後繼續執行其他操作,而無需等待任務完成。 它可以提高系統的併發性和響應能力。 但是,獲得結果很容易導致堵塞。
以下是未來介面的一些常用方法:
1) Boolean cancel(Boolean Mayinterruptifrunning):取消任務的執行。如果正在執行任務,並且 MayInterruptifRunning 引數設定為 true,則嘗試中斷任務的執行。
2) boolean iscancelled():檢查任務是否已取消。
3) boolean isdone():判斷任務是否已經完成。
4) v get() 丟擲 interruptedexception, executionexception: 獲取任務的執行結果。如果任務尚未執行,則 get() 方法將阻塞,直到任務執行完畢。 如果在任務執行過程中發生異常,get() 方法會丟擲 executionexception,您可以使用 getcause() 方法獲取具體的異常資訊。
4) V get(long timeout, timeunit unit) 丟擲 interruptedException, executionException, TimeOutException: 獲取任務在指定時間內的執行結果,如果任務未在指定時間內執行,則丟擲 timeoutException 異常。
ExecutorService 的 submit 方法。
ExecutorService 是 J**A 提供的用於管理執行緒池的介面。 它可用於執行非同步任務和管理執行緒的生命週期。 submit 方法是由 ExecutorService 介面定義的方法,它將任務提交到執行緒池並獲取將來的物件來表示任務的執行結果。
具體來說,submit 方法用於將可呼叫或可執行的物件提交到執行緒池進行執行。 可呼叫物件是有結果的任務,而可執行物件是沒有結果的任務。 submit 方法將任務提交到執行緒池,並立即返回乙個 future 物件,通過該物件可以獲取任務執行的結果或取消任務的執行。
您可以通過 submit 方法輕鬆管理執行緒池中的任務,也可以使用 future 物件獲取任務的狀態和結果,也可以取消任務的執行。 通常,我們可以使用 submit 方法而不是 execute 方法,因為它具有更多的功能和靈活性。
submit 和 execute 之間的區別。
submit() 和 execute() 是 ExecutorService 介面用於將任務提交到執行緒池的兩種方法,它們有以下區別:
1)返回值型別不同:submit()方法返回乙個未來物件,可用於獲取任務的執行結果或取消任務的執行;另一方面,execute() 方法不返回值,也無法獲取任務執行的結果。
2)不同的異常處理:submit()方法可以捕獲任務執行過程中丟擲的異常,將異常封裝到以後的物件中,通過呼叫get()方法或get(long, timeunit)方法獲取任務的執行結果,如果任務丟擲異常,可以通過executionexception獲取異常資訊;execute() 方法無法處理任務引發的異常,如果任務引發異常,執行緒池會將異常記錄到控制台。
3)不同的引數型別:submit()方法接受可呼叫或可執行的物件作為引數,可呼叫是有返回值的任務,runnable是沒有返回值的任務;execute() 方法只接受可執行物件作為引數。 因此,如果你需要獲取任務執行的結果,你應該使用 submit() 方法,如果你不需要獲取結果,你可以使用 execute() 方法。
一般來說,submit() 方法比 execute() 方法更靈活,可以獲取任務的執行結果並捕獲任務中丟擲的異常,因此在處理需要獲取結果或處理異常的任務時,建議使用 submit() 方法。 對於不需要結果的簡單任務,可以使用 execute() 方法。
completablefuture
未來使用阻塞來獲取結果與非同步程式設計的設計理念背道而馳,輪詢方式會消耗不必要的 CPU 資源,因此 jdk8 設計了 completablefuture。
CompletableFuture保留了未來的優點,彌補了其不足。 也就是說,當非同步任務完成並且您需要繼續操作其結果時,您無需等待。 可以直接使用 thenaccept、thenapply、thencompose 等方式,將之前非同步處理的結果交給另乙個非同步事件處理執行緒進行處理。
CompletableFuture 對 get 方法的呼叫也將被阻止以獲取結果。
1. 建立非同步任務。
創造乙個可完成的未來
CompleTableFuture 提供了四種靜態方法來建立非同步操作。
未指定執行程式的方法使用 forkjoinpoolcommonpool() 作為其執行緒池非同步執行。
如果指定了執行緒池,則使用指定的執行緒池。
runasync 方法不支援返回值。
SupplyAsync 可以支援返回值。
任務是非同步的。
thenrun/thenrunasync
可完成的未來thenrun/thenrunasync通俗地說,方法是完成第乙個任務,然後做第二個任務。 也就是說,乙個任務執行完成後,執行**方法; 但是,第乙個和第二個任務沒有引數傳遞,第二個任務也沒有返回值。
thenrun 和 thenrunasync 有什麼區別?
如果在執行第乙個任務時沒有傳入自定義執行緒池,則 thenrun thenrunasync 自然會使用預設的內建 forkjoin 執行緒池,並且可能都使用相同的執行緒。
相反,如果執行第乙個任務,則傳入自定義執行緒池:
當呼叫 thenrun 方法執行第二個任務時,第二個任務和第乙個任務共享同乙個執行緒池,因此可以使用相同的執行緒。
呼叫 thenrunasync 執行第二個任務時,第乙個任務使用您自己的執行緒池,第二個任務使用分叉連線線程池。
注意:thenaccept 和 thenacceptasync、thenapply 和 thenapplyasync 等的區別與 thenrun 和 thenrunasync 相同。
thenaccept/thenacceptasync
completablefuture 的 thenaccept ThenAcceptAsync 方法表示,第乙個任務執行完畢後,執行第二個方法任務,但第乙個任務的執行結果會作為輸入引數傳遞給該方法,但該方法沒有返回值。
thenapply/thenapplyasync
completablefuture 的 thenapply thenapplyasync 方法表示,第乙個任務執行完畢後,執行第二個方法任務,但第乙個任務的執行結果會作為輸入引數傳遞給該方法,並且該方法有乙個返回值。
exceptionally
completablefuture 的 exceptionally 方法表示當任務執行異常時,執行 ** 處理方法,丟擲異常作為引數傳遞給 ** 方法,並且 ** 方法具有返回值。
whencomplete
completablefuture 的 whencomplete 方法表示,在執行乙個任務後,執行了 ** 方法,並將任務結果用作 ** 方法的輸入引數,** 方法沒有返回值,whencomplete 方法返回的 completablefuture 的結果是第乙個任務的結果。
handle
completablefuture 的 handle 方法表示執行乙個任務後,執行 ** 方法,並將任務結果用作 ** 方法的輸入引數,** 方法有乙個返回值,handle 方法返回的 completablefuture 結果是 ** 方法的執行結果。
handle 和 thenapply 之間的區別。
thenapply:當任務發生異常時不,它不會轉到然後申請
handle:任務異常是的輸入控制代碼以處理異常。
3.多工組合**。
和投資組合關係。
ThenCombine ThenAcceptBoth RunAfterBorne 表示:當任務 1 和任務 2 都完成時,將執行任務 3。
不同之處在於 runafterboth 不使用結果作為方法引數,也不返回值。
ThenAcceptBoth:將兩個任務的執行結果作為方法引數傳遞給指定的方法,並且沒有返回值。
thencombine:將兩個任務的執行結果作為方法引數傳遞給指定的方法,並有乙個返回值。
或組合關係。
applytoeither accepteither runafter兩者都表示:兩個任務,只要完成乙個任務,就會執行第三個任務
區別在於:runaftereither:執行結果不作為方法引數使用,沒有返回值。
accepteither:已完成的任務將作為方法輸入引數傳遞給指定的方法,不帶返回值。
applytoeither:完成的任務將作為帶有返回值的方法輸入引數傳遞給指定的方法。
多工組合。
「allof」:等待所有任務完成並執行新任務。
「anyof」:完成一項任務後,將執行一項新任務。
4.completablefuture的使用注意事項。
1)future需要獲取返回值來獲取異常資訊。
future 需要獲取返回值來獲取異常資訊。 如果不新增 get() join() 方法,請考慮是否新增 try...。catch...或者使用 exceptionally 方法。
2) completablefuture 的 get() 方法被阻止。
completablefuture 的 get() 方法是阻塞的,如果用它來獲取非同步呼叫的返回值,則需要新增超時。
3)執行緒池的注意事項。
可以在 completablefuture 中使用預設執行緒池。 當大量請求傳入時,如果處理邏輯複雜,響應速度會很慢。 一般情況下,建議您使用自定義執行緒池來優化執行緒池配置引數。
future 與 completablefuture。
未來:我們的目標是獲得非同步任務的結果,但對於未來,我們只能通過使用 get 方法或無限迴圈來判斷是否完成。 異常情況更難處理。
completablefuture:只要我們設定了 ** 函式,就可以實現:
1.任務一完成,我們設定的功能就被執行了(無需考慮任務何時完成)。
2.如果發生異常,將執行處理異常的相同函式,甚至是預設返回值(更耗費人力)。
如果你有複雜的任務,比如依賴問題、組合問題等,也可以寫乙個處理函式來處理它(可以處理複雜的任務)。
當前 ** 問題。
1. 使用 Spring 執行緒池,統一管理執行緒。
如果介面頻繁訪問,則每次訪問都會建立乙個新的執行緒池,這可能會導致訪問時間過長和記憶體耗盡。
如果不呼叫 shutdown() 方法關閉執行緒池,可能會導致資源洩漏,或者程式可能無法正常退出。
Spring 執行緒池。
使用 thenaccept of completablefuture 可以避免阻塞。
在這種情況下,主線程不需要獲取返回值,先完成將附件儲存到伺服器的任務,然後將第乙個任務的“檔案路徑”作為第二個任務的輸入引數儲存在 fjxx 表中。
completablefuture 使用自定義執行緒池。
設定超時時間。
invokeall() 方法的超時時間與每個任務的執行時間沒有直接關係,因此在使用 invokeall() 方法時,需要根據任務數量和執行時間合理設定超時時間,以避免出現超時時間過長或過短的情況, 這會導致程式效能下降或任務無法完成。
呼叫未來後get() 方法獲取任務執行結果時,還可以設定超時時間和時間單位,防止整個程式因任務執行時間過長而做出響應。
冗餘邏輯。
2月** 動態激勵計畫