欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

深入了解Java語(yǔ)言中的并發(fā)性選項(xiàng)有何不同

 更新時(shí)間:2019年06月12日 11:26:22   作者:Neal Ford  
這篇文章主要介紹了深入了解Java語(yǔ)言中的并發(fā)性選項(xiàng)有何不同,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,,需要的朋友可以參考下

前言

Java™ 工程師在努力讓并發(fā)性容易為開(kāi)發(fā)人員所用。盡管做了不少的改進(jìn),但并發(fā)性仍然是 Java 平臺(tái)的一個(gè)復(fù)雜、容易出錯(cuò)的部分。一部分復(fù)雜之處在于理解語(yǔ)言本身中的并發(fā)性的低級(jí)抽象,這些抽象在您的代碼中填滿(mǎn)了同步的代碼塊。另一個(gè)復(fù)雜之處來(lái)自一些新庫(kù),比如 fork/join,這些庫(kù)在某些場(chǎng)景中非常有用,但在其他場(chǎng)景中收效甚微。了解容易混亂的大量低級(jí)選項(xiàng)需要專(zhuān)業(yè)經(jīng)驗(yàn)和時(shí)間。

脫離 Java 語(yǔ)言的優(yōu)勢(shì)之一是,能夠改善和簡(jiǎn)化并發(fā)性等區(qū)域。每種 Java 下一代語(yǔ)言都為此問(wèn)題提供了獨(dú)特的答案,利用了該語(yǔ)言的默認(rèn)編程風(fēng)格。在本期文章中,我首先將會(huì)介紹函數(shù)式編程風(fēng)格的優(yōu)勢(shì):輕松并行化。我會(huì)深入分析 Scala 和 Groovy 的細(xì)節(jié)(下一期文章將全面介紹 Clojure)。然后介紹 Scala actor。

完美數(shù)

數(shù)學(xué)家尼科馬庫(kù)斯(誕生于公元前 6 世紀(jì))將自然數(shù)分為惟一的完美數(shù)(perfect number)、過(guò)剩數(shù)(abundant number) 或虧數(shù)(deficient number)。一個(gè)完美數(shù)等于它的正因數(shù)(不包括它本身)之和。例如,6 是一個(gè)完美數(shù),因?yàn)樗囊驍?shù)是 1、2、3 和 6,28 也是完美數(shù) (28 = 1 + 2 + 4 + 7 + 14)。過(guò)剩數(shù)的因素之和大于該數(shù),虧數(shù)的因數(shù)之和小于該數(shù)。

這里使用完美數(shù)分類(lèi)法是為了方便介紹。除非要處理大量數(shù)字,是否查找因素對(duì)于從并行化中獲益而言是一個(gè)微不足道的問(wèn)題。使用更多線(xiàn)程可帶來(lái)一些益處,但線(xiàn)程之間的切換開(kāi)銷(xiāo)對(duì)細(xì)粒度的作業(yè)而言代價(jià)很高。

讓現(xiàn)有代碼并行化

在 “函數(shù)式編碼風(fēng)格” 那一期的文章中,我們鼓勵(lì)您使用更高級(jí)的抽象,比如化簡(jiǎn)、映射和過(guò)濾器,而不是迭代。此方法的優(yōu)勢(shì)之一是容易并行化。

我的 函數(shù)式思維 系列的讀者熟悉包含完美數(shù) 的數(shù)字分類(lèi)模式(參見(jiàn) 完美數(shù) 邊欄)。我在該系列中展示的任何解決方案都沒(méi)有利用并發(fā)性。但是因?yàn)檫@些解決方案使用了轉(zhuǎn)換函數(shù),比如 map,所以我可以在每種 Java.net 語(yǔ)言中做極少的工作來(lái)創(chuàng)建并行化的版本。

清單 1 是完美數(shù)分類(lèi)器的一個(gè) Scala 示例。

清單 1. Scala 中的并行完美數(shù)分類(lèi)器

object NumberClassifier {
def isFactor(factor: Int, number: Int) =
number % factor == 0
def factors(number: Int) = {
val factorsBelowSqrt = (1 to Math.sqrt(number).toInt).par.filter (isFactor(_, number))
val factorsAboveSqrt = factorsBelowSqrt.par.map(number / _)
(factorsBelowSqrt ++ factorsAboveSqrt).toList.distinct
}
def sum(factors: Seq[Int]) =
factors.par.foldLeft(0)(_ + _)
def isPerfect(number: Int) =
sum(factors(number)) - number == number
}

清單 1 中的 factors() 方法返回一個(gè)數(shù)的因數(shù)列表,使用 isFactor() 方法過(guò)濾所有可能的值。factors() 方法使用了我在 “函數(shù)式思維:轉(zhuǎn)換和優(yōu)化” 中更詳細(xì)地介紹的一種優(yōu)化。簡(jiǎn)單來(lái)講,過(guò)濾每個(gè)數(shù)來(lái)查找因素的效率很低,因?yàn)楦鶕?jù)定義,一個(gè)因數(shù)是其乘積等于目標(biāo)數(shù)的兩個(gè)數(shù)之一。

相反,我僅過(guò)濾不超過(guò)目標(biāo)數(shù)的平方根的數(shù),然后通過(guò)將目標(biāo)數(shù)除以每個(gè)小于平方根的因數(shù)來(lái)生成對(duì)稱(chēng)因數(shù)列表。在 清單 1 中,factorsBelowSqrt 變量包含過(guò)濾操作的結(jié)果。factorsAboveSqrt 的值是現(xiàn)有列表的映射,用于生成這些對(duì)稱(chēng)值。最后,factors() 的返回值是一個(gè)串聯(lián)的列表,它從一個(gè)并行的List 轉(zhuǎn)換為常規(guī)的 List。

請(qǐng)注意,清單 1 中添加了 par 修飾符。該修飾符會(huì)導(dǎo)致 filter、map 和 foldLeft 并行運(yùn)行,從而能夠使用多個(gè)線(xiàn)程來(lái)處理請(qǐng)求。par 方法(在整個(gè) Scala 集合庫(kù)中都是一致的)將該序列轉(zhuǎn)換為并行序列。因?yàn)閮煞N類(lèi)型的序列反映了它們的簽名,所以 par 函數(shù)變成了并行化某個(gè)操作的臨時(shí)方式。

在 Scala 中并行化常見(jiàn)問(wèn)題的簡(jiǎn)單性,在語(yǔ)言設(shè)計(jì)和函數(shù)模式上都經(jīng)過(guò)證實(shí)。函數(shù)式編程鼓勵(lì)使用通用的函數(shù),比如 map、filter 和 reduce,運(yùn)行時(shí)以不可見(jiàn)的方式可以進(jìn)一步優(yōu)化它們。Scala 語(yǔ)言設(shè)計(jì)人員考慮到了這些優(yōu)化,最終產(chǎn)生了集合 API 的設(shè)計(jì)。

邊緣情況

在 清單 1 的 factors() 方法實(shí)現(xiàn)中,整數(shù)的平方根(例如,16 的平方根:4)顯示在兩個(gè)列表中。因此,factors() 方法返回的最后一行是對(duì) distinct 函數(shù)的調(diào)用,它從列表中刪除了重復(fù)值。您也可以在每一處都使用 Set,而不是只在列表中使用它,但 List 常常擁有 Set 中所沒(méi)有的有用函數(shù)。

Groovy 也允許輕松地修改現(xiàn)有的函數(shù)代碼,通過(guò) GPars 庫(kù)讓它并行化,該庫(kù)捆綁在各個(gè) Groovy 發(fā)行版中。GPars 框架在內(nèi)置的 Java 并行性原語(yǔ)之上創(chuàng)建有用的抽象,常常將它們包裝在語(yǔ)法糖中。GPars 提供了令人眼花繚亂的并行機(jī)制,其中一種機(jī)制可用于分配線(xiàn)程池,然后將操作分布到這些池中。清單 2 中給出了一個(gè)使用 Groovy 編寫(xiě)的,使用 GPars 線(xiàn)程池的完美數(shù)分類(lèi)器。

清單 2. Groovy 中的并行完美數(shù)分類(lèi)器

class NumberClassifierPar {
static def factors(number) {
GParsPool.withPool {
def factors = (1..round(sqrt(number) + 1)).findAllParallel { number % it == 0 }
(factors + factors.collectParallel { number / it }).unique()
}
}
static def sumFactors(number) {
factors(number).inject(0, { i, j -> i + j })
}
static def isPerfect(number) {
sumFactors(number) - number == number
}
}

清單 2 中的 factors() 方法使用了與 清單 1 相同的算法:它生成不超過(guò)目標(biāo)數(shù)的平方根的所有因數(shù),然后生成剩余的因數(shù)并返回串聯(lián)的集合。與 清單 1 中一樣,我使用 unique() 方法來(lái)確保整數(shù)的平方根不會(huì)生成重復(fù)值。

無(wú)需像 Scala 中一樣放大集合來(lái)創(chuàng)建對(duì)稱(chēng)并行版本,Groovy 的設(shè)計(jì)人員創(chuàng)建了該語(yǔ)言的轉(zhuǎn)換方法的 xxxParallel() 版本(例如 findAllParallel() 和 collectParallel())。但除非這些方法包裝在 GPars 線(xiàn)程池代碼塊中,否則它們不會(huì)起作用。

在 清單 2 中,我創(chuàng)建了一個(gè)線(xiàn)程池,調(diào)用 GParsPool.withPool 創(chuàng)建一個(gè)代碼塊,支持在該代碼塊中使用 xxxParallel() 方法。withPool 方法存在其他變體。例如,您可指定池中的線(xiàn)程數(shù)量。

Clojure 通過(guò) 化簡(jiǎn)器 庫(kù)提供了一種類(lèi)似的臨時(shí)并行化機(jī)制。使用轉(zhuǎn)換函數(shù)的化簡(jiǎn)器版本來(lái)實(shí)現(xiàn)自動(dòng)并行化,例如,
使用 r/map 代替 map。(r/ 是化簡(jiǎn)器命名空間。)化簡(jiǎn)器的實(shí)現(xiàn)是 Clojure 的語(yǔ)法靈活性中的一個(gè)引人注目的案例分析,它通過(guò)極小的更改實(shí)現(xiàn)了強(qiáng)大的添加功能。

Scala 中的 actor

Scala 包含眾多并發(fā)性和并行性機(jī)制。一種較流行的機(jī)制是 actor 模型,它提供了將工作分布到線(xiàn)程上的優(yōu)勢(shì),而沒(méi)有同步的復(fù)雜性。在概念上,actor 有能力完成工作,然后將一個(gè)非阻塞的結(jié)果發(fā)送給協(xié)調(diào)器。要?jiǎng)?chuàng)建一個(gè) actor,需要?jiǎng)?chuàng)建 Actor 類(lèi)的子類(lèi)并實(shí)現(xiàn) act() 方法。通過(guò)使用 Scala 的語(yǔ)法糖,可繞過(guò)許多定義儀式,在代碼塊內(nèi)定義 actor。

我沒(méi)有為 清單 1 中的數(shù)字分類(lèi)器執(zhí)行的一種優(yōu)化是,使用線(xiàn)程對(duì)作業(yè)的因數(shù)查找部分進(jìn)行分區(qū)。如果我的計(jì)算機(jī)上有 4 個(gè)處理器,我可為每個(gè)處理器創(chuàng)建一個(gè)線(xiàn)程并拆分工作。例如,如果我嘗試找到數(shù)字 16 的因數(shù)之和,那么我可以安排處理器 1 來(lái)查找從 1 到 4 的因數(shù)(并求和),安排處理器 2 來(lái)處理 5 到 8,依此類(lèi)推。使用 actor 是一種自然的選擇:我為每個(gè)范圍創(chuàng)建了一個(gè) actor,獨(dú)立地執(zhí)行每個(gè) actor(通過(guò)語(yǔ)法糖隱式執(zhí)行或通過(guò)調(diào)用它的 act() 方法來(lái)顯式執(zhí)行),然后收集結(jié)果,如清單 3 所示。

清單 3. 使用 Scala 中的 actor 識(shí)別完美數(shù)

object NumberClassifier extends App {
def isPerfect(candidate: Int) = {
val RANGE = 10000
val numberOFPartitions = (candidate.toDouble / RANGE).ceil.toInt
val coordinator = self
for (i <- 0 until numberOFPartitions) {
val lower = i * RANGE + 1
val upper = candidate.min((i + 1) * RANGE)
actor {
var partialSum = 0
for (j <- lower to upper)
if (candidate % j == 0) partialSum += j
coordinator ! partialSum
}
}
var responsesExpected = numberOFPartitions
var sum = 0
while (responsesExpected > 0) {
receive {
case partialSum : Int =>
responsesExpected -= 1
sum += partialSum
}
}
sum == 2 * candidate
}
}

為了保持此示例的簡(jiǎn)單性,我將 isPerfect() 編寫(xiě)為單個(gè)完整的函數(shù)。我首先基于常量 RANGE 創(chuàng)建了一些分區(qū)。其次,我需要一種方式來(lái)收集 actor 所生成的消息。在 coordinator 變量中,我有一個(gè)引用可供 actor 向其發(fā)送消息,其中 self 是 Actor 的一個(gè)成員,表示 Scala 中獲取線(xiàn)程標(biāo)識(shí)符的可靠方式。

我然后為分區(qū)編號(hào)創(chuàng)建一個(gè)循環(huán),使用 RANGE 偏移來(lái)生成范圍的下限和上限。接下來(lái),為該范圍創(chuàng)建一個(gè) actor,使用 Scala 的語(yǔ)法糖來(lái)避免正式的類(lèi)定義。在 actor 內(nèi),我為 partialSum 創(chuàng)建了一個(gè)臨時(shí)保存器,然后分析該范圍,將找到的因數(shù)收集到 partialSum 中。收集部分和(此范圍內(nèi)的所有因數(shù)的和)后, (coordinator ! partialSum) 向協(xié)調(diào)器發(fā)回一條消息,使用感嘆號(hào)運(yùn)算符。(這種消息傳遞語(yǔ)法的靈感來(lái)源于 Erlang 語(yǔ)言,用作一種對(duì)另一個(gè)線(xiàn)程執(zhí)行非阻塞調(diào)用的途徑。)

接下來(lái),我啟動(dòng)了一個(gè)循環(huán),等待所有 actor 完成處理。在等待過(guò)程中,我進(jìn)入了一個(gè) receive 代碼塊。在該代碼塊內(nèi),我想要一條 Int 消息,我在本地將它分配給 partialSum,然后遞減想要的響應(yīng)數(shù)量,將該部分添加到總和中。所有 actor 完成且報(bào)告結(jié)果后,該方法的最后一行將該和與候選數(shù)的 2 倍相比較。如果比較結(jié)果為 true,那么我的候選數(shù)就是一個(gè)完美數(shù),該函數(shù)的返回值為 true。

actor 的一個(gè)不錯(cuò)的優(yōu)勢(shì)是所有權(quán)分區(qū)。每個(gè) actor 都有一個(gè) partialSum 局部變量,但它們從不彼此聯(lián)系。通過(guò)協(xié)調(diào)器收到消息時(shí),底層執(zhí)行機(jī)制是不可見(jiàn)的:您創(chuàng)建了一個(gè) receive 塊,其他實(shí)現(xiàn)細(xì)節(jié)是不可見(jiàn)的。

Scala 中的 actor 機(jī)制是 Java 下一代語(yǔ)言封裝 JVM 的現(xiàn)有工具并使用一致的抽象來(lái)擴(kuò)展它們的優(yōu)秀示例。用 Java 語(yǔ)言編寫(xiě)類(lèi)似的代碼,并使用低級(jí)并發(fā)性原語(yǔ),這些操作都需要非常復(fù)雜地協(xié)調(diào)多個(gè)線(xiàn)程。Scala 中的 actor 隱藏了所有復(fù)雜性,留下的是容易理解的抽象。

結(jié)束語(yǔ)

Java 下一代語(yǔ)言都為 Java 語(yǔ)言中的并發(fā)性難題提供了答案,而且每種語(yǔ)言以不同方式解決了這些問(wèn)題。在本期文章中,我演示了所有三種 Java 下一代語(yǔ)言如何實(shí)現(xiàn)臨時(shí)并行化。我還演示了 Scala 中的 actor 模型,構(gòu)建了一個(gè)數(shù)字分類(lèi)器來(lái)并行計(jì)算因數(shù)之和。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java拼接list字符串的實(shí)戰(zhàn)記錄

    Java拼接list字符串的實(shí)戰(zhàn)記錄

    這篇文章主要給大家介紹了關(guān)于Java拼接list字符串的相關(guān)資料,java生產(chǎn)和開(kāi)發(fā)中經(jīng)常需要將字符串List、數(shù)字List進(jìn)行拼接,以作為輸出對(duì)象或查詢(xún)條件,文中給出了代碼示例,需要的朋友可以參考下
    2023-08-08
  • Java設(shè)計(jì)模式之觀察者模式observer?pattern詳解

    Java設(shè)計(jì)模式之觀察者模式observer?pattern詳解

    這篇文章主要介紹了Java設(shè)計(jì)模式之觀察者模式observer?pattern詳解,當(dāng)一個(gè)對(duì)象發(fā)生數(shù)據(jù)變化時(shí),通知其他相關(guān)的一系列對(duì)象,接受到通知的對(duì)象根據(jù)該對(duì)象的變化進(jìn)行相應(yīng)處理以響應(yīng)變化的過(guò)程,需要的朋友可以參考下
    2023-12-12
  • Java 入門(mén)圖形用戶(hù)界面設(shè)計(jì)之事件處理上

    Java 入門(mén)圖形用戶(hù)界面設(shè)計(jì)之事件處理上

    圖形界面(簡(jiǎn)稱(chēng)GUI)是指采用圖形方式顯示的計(jì)算機(jī)操作用戶(hù)界面。與早期計(jì)算機(jī)使用的命令行界面相比,圖形界面對(duì)于用戶(hù)來(lái)說(shuō)在視覺(jué)上更易于接受,本篇精講Java語(yǔ)言中關(guān)于圖形用戶(hù)界面的事件處理
    2022-02-02
  • Spring Security表單配置過(guò)程分步講解

    Spring Security表單配置過(guò)程分步講解

    SpringSecurity的配置基于WebSecurityConfigurerAdapter的實(shí)現(xiàn)類(lèi),我們這里主要講基本配置,即configure(HttpSecurity http)方法的配置,其實(shí)大都有默認(rèn)值,我們可以直接用默認(rèn)值,也可以自己設(shè)置
    2023-01-01
  • springboot項(xiàng)目中后端接收前端傳參的方法示例詳解

    springboot項(xiàng)目中后端接收前端傳參的方法示例詳解

    這篇文章主要介紹了springboot項(xiàng)目中一些后端接收前端傳參的方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-06-06
  • 解決mapper接口無(wú)法映射mapper.xml的問(wèn)題

    解決mapper接口無(wú)法映射mapper.xml的問(wèn)題

    這篇文章主要介紹了解決mapper接口無(wú)法映射mapper.xml的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • 源碼解析帶你了解LinkedHashMap

    源碼解析帶你了解LinkedHashMap

    大多數(shù)情況下,只要不涉及線(xiàn)程安全問(wèn)題,Map基本都可以使用HashMap,不過(guò)HashMap有一個(gè)問(wèn)題,就是迭代HashMap的順序并不是HashMap放置的順序,也就是無(wú)序。HashMap的這一缺點(diǎn)往往會(huì)帶來(lái)困擾,所以L(fǎng)inkedHashMap就閃亮登場(chǎng)了,這篇文章通過(guò)源碼解析帶你了解LinkedHashMap
    2021-09-09
  • 解決java項(xiàng)目jar打包后讀取文件失敗的問(wèn)題

    解決java項(xiàng)目jar打包后讀取文件失敗的問(wèn)題

    這篇文章主要介紹了解決java項(xiàng)目jar打包后讀取文件失敗的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • 詳談Java中net.sf.json包關(guān)于JSON與對(duì)象互轉(zhuǎn)的坑

    詳談Java中net.sf.json包關(guān)于JSON與對(duì)象互轉(zhuǎn)的坑

    下面小編就為大家分享一篇Java中net.sf.json包關(guān)于JSON與對(duì)象互轉(zhuǎn)的坑,具有很好的參考價(jià)值,希望對(duì)大家有所幫助
    2017-12-12
  • 一個(gè)簡(jiǎn)易的Java多頁(yè)面隊(duì)列爬蟲(chóng)程序

    一個(gè)簡(jiǎn)易的Java多頁(yè)面隊(duì)列爬蟲(chóng)程序

    這篇文章主要為大家詳細(xì)介紹了一個(gè)多頁(yè)面的java爬蟲(chóng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-08-08

最新評(píng)論