Java 8中的并行和异步编程
并行代碼是在多個(gè)線程上運(yùn)行的代碼,曾經(jīng)是許多經(jīng)驗(yàn)豐富的開發(fā)人員的噩夢,但是Java 8帶來了許多更改,這些更改應(yīng)該使這種提高性能的技巧更加易于管理。
并行流
在Java 8之前,并行(或并發(fā))代碼與順序代碼之間存在很大差異。 調(diào)試非順序代碼也非常困難。 只需像通常那樣設(shè)置一個(gè)斷點(diǎn)并按照流程進(jìn)行操作,就可以刪除并行方面,如果這是導(dǎo)致該錯(cuò)誤的原因,那么這是一個(gè)問題。
幸運(yùn)的是,Java 8為我們提供了流,這是自Bean以來對Java開發(fā)人員而言最大的事情。 如果您不知道它們是什么,則Stream API可以處理功能問題中的元素序列。 (在這里檢查流與.NET的LINQ之間的比較。)流的優(yōu)點(diǎn)之一是代碼的結(jié)構(gòu)保持不變:無論是順序的還是并發(fā)的,它都保持可讀性。
為了使您的代碼并行運(yùn)行,您只需使用.parallelStream()而不是.stream() (或者,如果您不是流的創(chuàng)建者,則可以使用stream .parallel() )。
但是,僅僅因?yàn)樗苋菀?#xff0c;并不意味著并行代碼始終是最佳選擇。 您應(yīng)該始終考慮對代碼使用并發(fā)是否有意義。 該決定中最重要的因素將是速度:僅當(dāng)并發(fā)使您的代碼比其順序?qū)?yīng)的代碼更快時(shí)才使用并發(fā)。
速度問題
并行代碼通過使用多個(gè)線程而不是順序代碼使用的單個(gè)線程而獲得了速度優(yōu)勢。 確定創(chuàng)建多少個(gè)線程可能是一個(gè)棘手的問題,因?yàn)楦嗟木€程并不總是會導(dǎo)致更快的代碼:如果使用太多的線程,則代碼的性能實(shí)際上可能會下降。
有幾個(gè)規(guī)則可以告訴您選擇多少線程。 這主要取決于您要執(zhí)行的操作類型以及可用內(nèi)核的數(shù)量。
計(jì)算密集型操作應(yīng)使用少于或等于內(nèi)核數(shù)的線程數(shù),而IO密集型操作(如復(fù)制文件)對CPU無用,因此可以使用更多線程。 該代碼不知道哪種情況適用,除非您告訴它該怎么做。 否則,它將默認(rèn)為線程數(shù)等于內(nèi)核數(shù)。
在兩種主要情況下,并行運(yùn)行代碼而不是順序運(yùn)行代碼很有用:耗時(shí)的任務(wù)和在大集合上運(yùn)行的任務(wù)。 Java 8帶來了一種處理大集合的新方法,即使用流。 流具有惰性的內(nèi)置效率:它們使用惰性評估,通過不做不必要的事情來節(jié)省資源。 這與并行性不同,只要它運(yùn)行得更快,它就不會在乎資源。 因此,對于大型集合,您可能不需要經(jīng)典的并行性。
================================================== ====================
異步
JavaScript的教訓(xùn)
Java開發(fā)人員很少會說他們從看過JavaScript中學(xué)到了什么,但是在異步編程方面,JavaScript實(shí)際上是正確的。 作為一種從根本上異步的語言,JavaScript經(jīng)驗(yàn)豐富,如果實(shí)施不好,它會帶來多大的痛苦。 它從回調(diào)開始,后來被promise取代。 許諾的一個(gè)重要好處是它有兩個(gè)“通道”:一個(gè)用于數(shù)據(jù),另一個(gè)用于錯(cuò)誤。 JavaScript承諾可能看起來像這樣:
func .then(f1) .catch(e1) .then(f2) .catch(e2);因此,當(dāng)原始函數(shù)獲得成功結(jié)果時(shí),將調(diào)用f1,但是如果引發(fā)錯(cuò)誤,則將調(diào)用e1。 這可能會將其帶回到成功軌道(f2),或?qū)е铝硪粋€(gè)錯(cuò)誤(e2)。 您可以從數(shù)據(jù)跟蹤到錯(cuò)誤跟蹤再返回。
JavaScript承諾的Java版本稱為CompletableFuture 。
未來發(fā)展
CompletableFuture同時(shí)實(shí)現(xiàn)Future和CompletionStage接口。 Java8之前就已經(jīng)存在Future ,但是它本身對開發(fā)人員并不十分友好。 您只能使用.get()方法獲得異步計(jì)算的結(jié)果,該方法會阻塞其余部分(使異步部分大部分時(shí)間變得毫無意義),并且您需要手動實(shí)現(xiàn)每種情況。 添加CompletionStage接口是使Java異步編程可行的突破。
CompletionStage是一個(gè)承諾,即最終將完成計(jì)算的承諾。 它包含許多方法,可讓您附加將在完成時(shí)執(zhí)行的回調(diào)。 現(xiàn)在我們可以處理結(jié)果而不會阻塞。
有兩種主要方法可讓您啟動代碼的異步部分: supplyAsync如果您想對方法的結(jié)果做一些事情)和runAsync如果您不想這樣做)。
CompletableFuture.runAsync(() → System.out.println("Run async in completable future " + Thread.currentThread())); CompletableFuture.supplyAsync(() → 5);回呼
現(xiàn)在,您可以添加這些回調(diào)以處理supplyAsync的結(jié)果
CompletableFuture.supplyAsync(() → 5) .thenApply(i → i * 3) .thenAccept(i → System.out.println(“The result is “ + i) .thenRun(() → System.out.println("Finished."));.thenApply與.thenApply的.map函數(shù)相似:它執(zhí)行轉(zhuǎn)換。 在上面的示例中,它將結(jié)果(5)乘以3。然后將結(jié)果(15)進(jìn)一步傳遞給管道。
.thenAccept對結(jié)果執(zhí)行一種方法,而無需對其進(jìn)行轉(zhuǎn)換。 它也不會返回結(jié)果。 它將在控制臺上顯示“結(jié)果為15”。 可以將它與.foreach方法進(jìn)行流比較。
.thenRun不使用異步操作的結(jié)果,也不返回任何內(nèi)容,它只是等待調(diào)用其Runnable直到上一步完成為止。
異步處理
上述所有回調(diào)方法也都具有異步版本: thenRunAsync , thenApplyAsync等。這些版本可以在自己的線程上運(yùn)行,它們?yōu)槟峁┝祟~外的控制權(quán),因?yàn)槟梢愿嬖V它要使用哪個(gè)ForkJoinPool 。
如果您不使用異步版本,則所有回調(diào)將在同一線程上執(zhí)行。
當(dāng)事情出錯(cuò)時(shí)
當(dāng)出現(xiàn)問題時(shí),將使用exceptionally方法來處理異常。 您可以給它提供一個(gè)方法,該方法返回一個(gè)值以返回?cái)?shù)據(jù)軌道,或引發(fā)(新)異常。
… .exceptionally(ex → new Foo()) .thenAccept(this::bar);合并和撰寫
您可以使用thenCompose方法鏈接多個(gè)CompletableFutures 。 沒有它,結(jié)果將嵌套CompletableFutures 。 這使得thenCompose和thenApply像flatMap和map用于流。
CompletableFuture.supplyAsync(() -> "Hello") .thenCompose(s -> CompletableFuture .supplyAsync(() -> s + "World"));如果要合并兩個(gè)CompletableFutures的結(jié)果,則需要一個(gè)方便地稱為thenCombine的方法。
future.thenCombine(future2, Integer::sum) .thenAccept(value → System.out.println(value));如您在上面的示例中看到的那樣,可以使用所有喜歡的CompletionStage方法像普通的CompletableFuture一樣處理thenCombine中的回調(diào)結(jié)果。
結(jié)論
在尋求更快的代碼時(shí),并行編程不再是不可克服的障礙。 Java 8使該過程盡可能簡單明了,因此,可能從中受益的任何代碼都可以在所有線程上被拉,踢和尖叫,進(jìn)入多核未來,而實(shí)際上,這只是現(xiàn)在天。 我的意思是:這很容易做到,因此請嘗試一下,看看自己的優(yōu)勢。
翻譯自: https://www.javacodegeeks.com/2018/04/parallel-and-asynchronous-programming-in-java-8.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的Java 8中的并行和异步编程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: hibernate状态_Hibernat
- 下一篇: javaone_替代JavaOne 20