1. callable runnable future
Callable,有結(jié)果的同步行為夯缺,比如做蛋糕瘸羡,產(chǎn)生蛋糕
Runnable府阀,無結(jié)果的同步行為缆镣,比如喝牛奶,僅僅就是喝
Future试浙,異步封裝Callable/Runnable董瞻,比如委托給師傅(其他線程)去做糕點
CompletableFuture,封裝Future田巴,使其擁有回調(diào)功能钠糊,比如讓師傅主動告訴我蛋糕做好了
2. future的缺點
在java8以前,我們使用java的多線程編程,一般是通過Runnable中的run方法來完成,這種方式,有個很明顯的缺點,就是,沒有返回值,這時候,大家可能會去嘗試使用Callable中的call方法,然后用Future返回結(jié)果。
當(dāng)調(diào)用future的get()方法時,當(dāng)前主線程是堵塞的,這好像并不是我們想看到的,另一種獲取返回結(jié)果的方式是先輪詢,可以調(diào)用isDone,等完成再獲取,但這也不能讓我們滿意. 比如:很多個異步線程執(zhí)行時間可能不一致,我的主線程業(yè)務(wù)不能一直等著,這時候我可能會想要只等最快的線程執(zhí)行完或者最重要的那個任務(wù)執(zhí)行完,亦或者我只等1秒鐘,至于沒返回結(jié)果的線程我就用默認(rèn)值代替
3. 設(shè)計與實現(xiàn)
從CompletableFuture的使用方法可以看出壹哺,CompletableFuture主要是通過回調(diào)的方式實現(xiàn)異步編程抄伍,解決Future在使用過程中需要阻塞的問題。因此如何設(shè)計線程安全的高性能回調(diào)機(jī)制是CompletableFuture需要解決的核心問題斗躏。
設(shè)計模式類似觀察者模式:CompletableFuture是發(fā)布者逝慧,使用鏈表保存觀察者Completion昔脯。分析代碼后得知CompletableFuture的postComplete方法是通知方法啄糙,用于在CompletableFuture完成時通知觀察者,發(fā)送訂閱的數(shù)據(jù)云稚。Completion的tryFire方法用于處理CompletableFuture發(fā)布的結(jié)果隧饼。
4. 整體調(diào)用
5. 算法實現(xiàn)
如果算法中一個線程的失敗或掛起沒有導(dǎo)致其它的線程失敗或掛起,我們就說這個算法是非阻塞(nonblocking)的静陈。非阻塞算法可以讓多個線程在競爭相同資源時不會發(fā)生阻塞燕雁。如果算法中的每一步都至少有一個線程可以繼續(xù)執(zhí)行诞丽,我們就說這個算法是無鎖(lock-free)的。無鎖算法對死鎖和其他活躍度問題具有免疫性拐格。CompletableFuture使用了名為Treiber Stack的一種用cas操作解決并發(fā)沖突僧免,實現(xiàn)非阻塞無鎖并發(fā)棧的算法。
6. thenApply為例
后續(xù)任務(wù)入棧等待通知捏浊,通知必須得在入棧后才發(fā)送過來懂衩,否則可能導(dǎo)致永遠(yuǎn)等不到通知