編程范式巡禮第二季 并發(fā)那些事

編程范式巡禮第二季 并發(fā)那些事

繼續(xù)上周的編程范式話題弃舒,今天想聊一下并發(fā)范式癞埠。

并發(fā)也算一種范式?

真正的并發(fā)式編程状原,絕不只是調(diào)用線程API或使用synchronized、lock之類的關(guān)鍵字那么簡單苗踪。從宏觀的架構(gòu)設(shè)計颠区,到微觀的數(shù)據(jù)結(jié)構(gòu)、流程控制乃至算法通铲,相比通常的串行式編程都可能發(fā)生變化毕莱。毫不夸張的說,是又一場思想和技術(shù)上革命颅夺。

在日常開發(fā)中朋截,并發(fā)編程難度是比較高的,屬于高級程序員才能掌握的內(nèi)容吧黄。其難點在哪里部服,我們?nèi)粘A?xí)慣的是線性思維,這與并發(fā)編程的多維世界觀是不同的拗慨,提升思考的維度無疑是艱難廓八。但還好,在大神們的努力下胆描,已逐漸化繁為簡瘫想,這也是并發(fā)范式帶來的力量。在并發(fā)領(lǐng)域有許多的模型昌讲,讓我們來巡禮一下国夜。

模型1:線程與鎖

并發(fā)編程以資源共享和競爭為主線。這意味著程序設(shè)計將圍繞進(jìn)程的劃分與調(diào)度短绸、進(jìn)程之間的通信與同步等來展開车吹。合理的并發(fā)式設(shè)計需要諸多方面的權(quán)衡考量。

線程是對底層硬件過程的形式化醋闭,是并發(fā)編程的核心窄驹。不同的線程各自獨立運行,有如一個個的平行宇宙证逻。但是乐埠,并發(fā)編程并不僅僅串行化編程的疊加,主要的差異在于囚企,線程之間存在共享和競爭丈咐。共享資源會帶來哪些問題呢?

  • 問題1:臟讀

當(dāng)線程1對共享數(shù)據(jù)進(jìn)行修改時龙宏,線程2有可能會讀到處于中間狀態(tài)的數(shù)據(jù)棵逊,這個問題稱之為臟讀。

并發(fā)1
并發(fā)1

解決的思路比較簡單银酗,就是讓線程1僅提交最終修改結(jié)果辆影,在修改過程中產(chǎn)生并使用快照數(shù)據(jù)徒像。這種類似影分身的技術(shù)稱之為MVCC(Multi-Version Concurrency Control)。

并發(fā)2
并發(fā)2
  • 問題2:丟失更新

當(dāng)線程1對數(shù)據(jù)進(jìn)行修改時蛙讥,如果線程2同時修改锯蛀,由于采用了MVCC,雙方各自無法看到键菱,那最終提交時谬墙,很可能會造成其中一個線程結(jié)果與預(yù)期不一致今布,這個問題稱為丟失更新经备。
其解決方法是加鎖,在修改前進(jìn)行加鎖部默,一旦占用侵蒙,則第二個線程無法獲取。

并發(fā)3
并發(fā)3

臟讀和丟失更新是需要同時考慮的傅蹂,所以標(biāo)準(zhǔn)的多線程處理是同時使用到了MVCC和鎖這兩個技術(shù)纷闺。

并發(fā)4
并發(fā)4
  • 問題3:幻讀

在已解決了丟失更新和臟讀的情況下,下面要考慮多次讀取的情況份蝴。如下圖所示犁功,線程1對數(shù)據(jù)集進(jìn)行了多次讀取,但是部分?jǐn)?shù)據(jù)在線程2中進(jìn)行了更新婚夫,這時候出現(xiàn)了線程1在沒有任何作為的情況下浸卦,兩次讀取不一致的情況!0覆凇限嫌!這個問題稱為幻讀。

并發(fā)5
并發(fā)5

解決幻讀的方法是擴(kuò)大數(shù)據(jù)的鎖范圍时捌,不僅僅是更改過的記錄怒医,所有讀取的記錄都要加鎖。

并發(fā)6
并發(fā)6
  • 綜述

這就是目前我們最主流的并發(fā)與鎖的實現(xiàn)思路方法奢讨,有非常廣泛的使用稚叹。不知道大家讀完這段的感覺怎么,我看的時候拿诸,第一個感覺是復(fù)雜扒袖,真的非常的燒腦,由于大量概念的堆積對于初學(xué)者來說非常不友好佳镜;第二個感覺是矛盾僚稿,按照最終幻讀的解決方案,實際上就是放棄了程序間的并行蟀伸,繞了一圈蚀同,又回到了原點缅刽。正因為如此,目前主流的數(shù)據(jù)庫蠢络,實際上默認(rèn)都是放棄對于幻讀問題解決的衰猛,這也是開發(fā)上的一大坑。

綜合的來看刹孔,這種解決方式學(xué)習(xí)成本很高啡省,而且還沒能解決全部的問題,并不能讓人滿意髓霞。有沒有更好點的方法卦睹,讓我們繼續(xù)。

模型2:函數(shù)式編程與Lambda架構(gòu)

傳統(tǒng)并發(fā)模型中方库,最令人糾結(jié)的無疑就是共享數(shù)據(jù)訪問這塊了结序。若不爽,就另辟蹊徑纵潦。我們能不能不對共享數(shù)據(jù)進(jìn)行寫入呢?有什么樣的程序是只讀不寫的呢徐鹤,大神們已經(jīng)找到了答案,就是上周介紹的函數(shù)式編程邀层。

首先想說明的事返敬,純函數(shù)式的編程功能上并不完備,有非常多的缺陷寥院,但其有一個天然的適用場景劲赠,就是數(shù)學(xué)運算分析,也就是我們現(xiàn)在時常掛在嘴邊的大數(shù)據(jù)計算只磷。
由于拋棄掉了共享狀態(tài)经磅,其代碼的健壯性和擴(kuò)展性得到了大大的增強(qiáng),只要有足夠的計算資源就可以處理無限大的數(shù)據(jù)钮追。

函數(shù)式編程思維比較數(shù)學(xué)化预厌,難度是比較高的,在此基礎(chǔ)上元媚,誕生了Lambda框架轧叽,是對應(yīng)用模式的固化,有助于降低學(xué)習(xí)成本和大范圍推廣刊棕。Lambda框架既使用了可以進(jìn)行大規(guī)模批處理的MapReduce技術(shù)炭晒,也使用了可以快速處理數(shù)據(jù)并及時反饋的流處理技術(shù),這樣的混搭能夠為大數(shù)據(jù)問題提供擴(kuò)展性甥角、響應(yīng)性和容錯性都能優(yōu)秀的解決方案网严。

Lambda架構(gòu)也可以這樣來描述:在該架構(gòu)中,被讀取的數(shù)據(jù)是不可變的嗤无,在并行處理過程中數(shù)據(jù)會依次進(jìn)入批處理系統(tǒng)(batch system)與流處理系統(tǒng)震束。從邏輯上看怜庸,傳輸過程發(fā)生了兩次,一次是在批處理中垢村,一次是在流處理中割疾。在查詢時,當(dāng)這兩者都返回結(jié)果后嘉栓,才算是完成一次完整的查詢宏榕。

20140510204559203

模型3:Actor

函數(shù)式編程模型的應(yīng)用使得并發(fā)編程的應(yīng)用踏入了工業(yè)級,帶動了大數(shù)據(jù)的熱潮侵佃。但是其解決思路是拋棄了可變狀態(tài)麻昼,服務(wù)是有損的。對于必須提供無損服務(wù)的場景該如何進(jìn)行改進(jìn)呢趣钱。

從最一開始線程與鎖的模型中涌献,我們可以看到串行化是最重的解決方案,但是為了串行化首有,我們需要MVCC、鎖等一系列的工具枢劝,比較復(fù)雜井联,Actor模型就是用來簡化此類操作的。

Actor模型中抽象出了兩個概念A(yù)ctor和Mailbox您旁,Actor就是指代共享數(shù)據(jù)烙常,Mailbox管理數(shù)據(jù)的操作。對于每個Actor的操作鹤盒,要通過mailbox來進(jìn)行蚕脏,在mailbox端實現(xiàn)了隊列的控制,從而實現(xiàn)了序列化的效果侦锯。

AkkaComponentMatching

Actor模型會帶來一些額外的好處:

  1. 用Actor來定義共享數(shù)據(jù)驼鞭,邊界非常清晰,實現(xiàn)了與主線代碼的解耦尺碰,最大化減少了序列化的影響挣棕,可以有效提升性能。
  2. Actor中引入了消息的概念亲桥,是位置透明的洛心,天然支持了分布式的部署。
  3. 在概念清晰之后题篷,代碼得到了簡化词身,下面摘錄一段Actor的代碼,可以看到是封裝了并發(fā)相關(guān)的技術(shù)細(xì)節(jié)番枚,非常的簡潔法严。
class Pong extends Actor {
  def act() {
    var pongCount = 0
    while (true) {
      receive {
        case Ping =>
          if (pongCount % 1000 == 0)
            Console.println("Pong: ping " + pongCount)
          sender ! Pong
          pongCount = pongCount + 1
        case Stop =>
          Console.println("Pong: stop")
          exit()
      }
    }
  }
}

模型4:原子變量

很多情況下我們需要一個高效的璧瞬、線程安全的并發(fā)解決方案。高效意味著耗用資源要少渐夸,程序處理速度要快嗤锉;線程安全也非常重要,這個在多線程下能保證數(shù)據(jù)的正確性墓塌。有一個解決方案是原子變量瘟忱。

通常情況下,在Java里面苫幢,++i或者--i不是線程安全的访诱,這里面有三個獨立的操作:獲得變量當(dāng)前值,為該值+1/-1韩肝,然后寫回新的值触菜。在沒有額外資源可以利用的情況下,只能使用加鎖才能保證讀-改-寫這三個操作是“原子性”的哀峻。

下面是示例代碼:

public final int incrementAndGet() {
    for (;;) {
        int current = get();
        int next = current + 1;
        if (compareAndSet(current, next))
            return next;
    }
}

在這里采用了CAS操作涡相,每次從內(nèi)存中讀取數(shù)據(jù)然后將此數(shù)據(jù)和+1后的結(jié)果進(jìn)行CAS操作,如果成功就返回結(jié)果剩蟀,否則重試直到成功為止催蝗。而compareAndSet利用JNI來完成CPU指令的操作。

原子變量在一些對性能有極端要求的系統(tǒng)中(比如Jetty育特、Tomcat)有非常廣泛的應(yīng)用丙号,是一種精益求精的體現(xiàn),其在可靠性和性能方面表現(xiàn)很突出缰冤,但在易用性方面比較偏計算機(jī)思維犬缨,理解難度較大,并不夠簡潔棉浸,需要反復(fù)練習(xí)才能掌握怀薛。

小結(jié)

在今天的篇文章中,列舉了并發(fā)范式的四個主流模型:線程與鎖涮拗、函數(shù)式編程乾戏、Actor、原子變量三热」脑瘢可以看到,每個模型都是在功能就漾、性能和易用之間尋求了一種平衡呐能,并沒有一種模型在功能、性能和易用三方面同時達(dá)到最優(yōu),也就是說沒有銀彈摆出。
這是我們面對并發(fā)問題時的困境朗徊,也是挑戰(zhàn),也正說明了并發(fā)并不是一個簡單的線性問題偎漫,我們需要針對具體場景爷恳、具體問題進(jìn)行分析,尋找最適合的解決方法象踊,這也是開發(fā)人員需要養(yǎng)成的一種重要素養(yǎng)温亲。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市杯矩,隨后出現(xiàn)的幾起案子栈虚,更是在濱河造成了極大的恐慌,老刑警劉巖史隆,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件魂务,死亡現(xiàn)場離奇詭異,居然都是意外死亡泌射,警方通過查閱死者的電腦和手機(jī)粘姜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來魄幕,“玉大人相艇,你說我怎么就攤上這事〈吭桑” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵留储,是天一觀的道長翼抠。 經(jīng)常有香客問我,道長获讳,這世上最難降的妖魔是什么阴颖? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮丐膝,結(jié)果婚禮上量愧,老公的妹妹穿的比我還像新娘。我一直安慰自己帅矗,他們只是感情好偎肃,可當(dāng)我...
    茶點故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著浑此,像睡著了一般累颂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天紊馏,我揣著相機(jī)與錄音料饥,去河邊找鬼。 笑死朱监,一個胖子當(dāng)著我的面吹牛岸啡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播赫编,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼巡蘸,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了沛慢?” 一聲冷哼從身側(cè)響起赡若,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎团甲,沒想到半個月后逾冬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡躺苦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年身腻,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片匹厘。...
    茶點故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡嘀趟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出愈诚,到底是詐尸還是另有隱情她按,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布炕柔,位于F島的核電站酌泰,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏匕累。R本人自食惡果不足惜陵刹,卻給世界環(huán)境...
    茶點故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望欢嘿。 院中可真熱鬧衰琐,春花似錦、人聲如沸炼蹦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽框弛。三九已至辛辨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背斗搞。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工指攒, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人僻焚。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓允悦,卻偏偏與公主長得像,于是被迫代替她去往敵國和親虑啤。 傳聞我的和親對象是個殘疾皇子隙弛,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,675評論 2 359

推薦閱讀更多精彩內(nèi)容