日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

CompletableFuture不能被打断

發(fā)布時(shí)間:2023/12/3 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 CompletableFuture不能被打断 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

我已經(jīng)寫了很多有關(guān)InterruptedException和中斷線程的文章 。 簡(jiǎn)而言之,如果您沒有Future.cancel()調(diào)用Future.cancel()那么Future將終止待處理的get() ,但還將嘗試中斷基礎(chǔ)線程。 這是一個(gè)非常重要的功能,可以更好地利用線程池。 我還寫信總是比標(biāo)準(zhǔn)Future更喜歡CompletableFuture 。 事實(shí)證明,功能更強(qiáng)大的Future弟兄沒有那么優(yōu)雅地處理cancel() 。 考慮以下任務(wù),我們稍后將在整個(gè)測(cè)試中使用以下任務(wù):

class InterruptibleTask implements Runnable {private final CountDownLatch started = new CountDownLatch(1)private final CountDownLatch interrupted = new CountDownLatch(1)@Overridevoid run() {started.countDown()try {Thread.sleep(10_000)} catch (InterruptedException ignored) {interrupted.countDown()}}void blockUntilStarted() {started.await()}void blockUntilInterrupted() {assert interrupted.await(1, TimeUnit.SECONDS)}}

客戶端線程可以檢查InterruptibleTask以查看其是否已開始或被中斷。 首先,讓我們看一下InterruptibleTask對(duì)外部的cancel()反應(yīng):

def "Future is cancelled without exception"() {given:def task = new InterruptibleTask()def future = myThreadPool.submit(task)task.blockUntilStarted()and:future.cancel(true)when:future.get()then:thrown(CancellationException) }def "CompletableFuture is cancelled via CancellationException"() {given:def task = new InterruptibleTask()def future = CompletableFuture.supplyAsync({task.run()} as Supplier, myThreadPool)task.blockUntilStarted()and:future.cancel(true)when:future.get()then:thrown(CancellationException) }

到目前為止,一切都很好。 顯然, Future和CompletableFuture工作方式幾乎相同-在取消結(jié)果后檢索結(jié)果會(huì)引發(fā)CancellationException 。 但是myThreadPool線程呢? 我以為它會(huì)被游泳池打斷,從而被回收,我怎么了!

def "should cancel Future"() {given:def task = new InterruptibleTask()def future = myThreadPool.submit(task)task.blockUntilStarted()when:future.cancel(true)then:task.blockUntilInterrupted() }@Ignore("Fails with CompletableFuture") def "should cancel CompletableFuture"() {given:def task = new InterruptibleTask()def future = CompletableFuture.supplyAsync({task.run()} as Supplier, myThreadPool)task.blockUntilStarted()when:future.cancel(true)then:task.blockUntilInterrupted() }

第一個(gè)測(cè)試將普通的Runnable提交給ExecutorService并等待其啟動(dòng)。 稍后,我們?nèi)∠鸉uture并等待直到觀察到InterruptedException 。 當(dāng)基礎(chǔ)線程被中斷時(shí), blockUntilInterrupted()將返回。 但是,第二次測(cè)試失敗。 CompletableFuture.cancel()永遠(yuǎn)不會(huì)中斷基礎(chǔ)線程,因此盡管Future看起來好像已被取消,但后備線程仍在運(yùn)行,并且sleep()不會(huì)拋出InterruptedException 。 錯(cuò)誤或功能? 它已記錄在案 ,因此很遺憾地提供一個(gè)功能:

參數(shù): mayInterruptIfRunning –此值在此實(shí)現(xiàn)中無效,因?yàn)椴皇褂弥袛鄟砜刂铺幚怼?

您說RTFM,但是為什么CompletableFuture這樣工作? 首先,讓我們研究“舊的” Future實(shí)現(xiàn)與CompletableFuture有何不同。 從ExecutorService.submit()返回的FutureTask具有以下cancel()實(shí)現(xiàn)(我使用類似的非線程安全Java代碼刪除了Unsafe ,因此僅將其視為偽代碼):

public boolean cancel(boolean mayInterruptIfRunning) {if (state != NEW)return false;state = mayInterruptIfRunning ? INTERRUPTING : CANCELLED;try {if (mayInterruptIfRunning) {try {Thread t = runner;if (t != null)t.interrupt();} finally { // final statestate = INTERRUPTED;}}} finally {finishCompletion();}return true; }

FutureTask具有一個(gè)遵循該狀態(tài)圖的state變量:

在的情況下, cancel()我們可以進(jìn)入CANCELLED狀態(tài)或去INTERRUPTED通過INTERRUPTING 。 核心部分是我們拿runner線程(如果存在的,也就是說,如果當(dāng)前正在執(zhí)行的任務(wù)),我們盡量打斷它。 該分支負(fù)責(zé)急切和強(qiáng)制中斷已運(yùn)行的線程。 最后,我們必須通知阻塞的所有線程Future.get()中finishCompletion()這里無關(guān)緊要)。 因此,很明顯,多大的Future取消已經(jīng)運(yùn)行的任務(wù)。 那CompletableFuture呢? cancel()偽代碼:

public boolean cancel(boolean mayInterruptIfRunning) {boolean cancelled = false;if (result == null) {result = new AltResult(new CancellationException());cancelled = true;}postComplete();return cancelled || isCancelled(); }

令人失望的是,我們幾乎沒有將result設(shè)置為CancellationException ,而忽略了mayInterruptIfRunning標(biāo)志。 postComplete()也有類似的作用finishCompletion() -在通知未來注冊(cè)的所有懸而未決的回調(diào)。 它的實(shí)現(xiàn)相當(dāng)令人不快(使用非阻塞式Treiber stack ),但是它絕對(duì)不會(huì)中斷任何底層線程。

原因和含義

在CompletableFuture情況下,有限的cancel()不是錯(cuò)誤,而是設(shè)計(jì)決定。 CompletableFuture并非固有地綁定到任何線程,而Future幾乎總是代表后臺(tái)任務(wù)。 從零開始創(chuàng)建CompletableFuture ( new CompletableFuture<>() )是完美的,其中根本沒有要取消的底層線程。 我仍然不禁感到大多數(shù)CompletableFuture 都將具有關(guān)聯(lián)的任務(wù)和后臺(tái)線程。 在這種情況下, cancel()可能會(huì)出現(xiàn)故障。 我不再建議用CompletableFuture盲目地替換Future ,因?yàn)樗赡軙?huì)更改依賴cancel()的應(yīng)用程序的行為。 這意味著CompletableFuture故意違反了Liskov替換原則 -這是需要考慮的嚴(yán)重問題。

翻譯自: https://www.javacodegeeks.com/2015/03/completablefuture-cant-be-interrupted.html

總結(jié)

以上是生活随笔為你收集整理的CompletableFuture不能被打断的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。