二示罗、說說線程同步

線程同步概念想要解決的問題?

應用程序里面多個線程的存在引發(fā)了多個執(zhí)行線程安全訪問資源的潛在問題芝硬。兩個線程同時修改同一資源有可能以意想不到的方式互相干擾蚜点。這個現(xiàn)象被稱為"數(shù)據(jù)競爭"。

線程之間不能且不應該是完全獨立的拌阴,互不干擾的(要不設計來干嘛绍绘?)。所以在線程必須交互的情況下,你需要使用同步工具陪拘,來確保當它們交互的時候是安全的厂镇。

同步工具

為了防止不同線程意外修改數(shù)據(jù),你可以設計你的程序沒有同步問題左刽,或你也可以使用同步工具捺信。盡管完全避免出現(xiàn)同步問題相對更好一點,但是幾乎總是無法實現(xiàn)悠反。

1.原子操作

原子操作是同步的一個簡單的形式残黑,它處理簡單的數(shù)據(jù)類型。原子操作的優(yōu)勢是它們不妨礙競爭的線程斋否。對于簡單的操作梨水,比如遞增一個計數(shù)器,原子操作比使用鎖具有更高的性能優(yōu)勢茵臭。

2.內(nèi)存屏障和Volatile變量

內(nèi)存屏障(memory barrier)是一個使用來確保內(nèi)存操作按照正確的順序工作的非阻塞的同步工具疫诽。內(nèi)存屏障的作用就像一個柵欄,迫使處理器來完成位于障礙前面的任何加載和存儲操作旦委,才允許它執(zhí)行位于屏障之后的加載和存儲操作奇徒。內(nèi)存屏障同樣使用來確保一個線程(但對另外一個線程可見)的內(nèi)存操作總是按照預定的順序完成。如果在這些地方缺少內(nèi)存屏障有可能讓其他線程看到看似不可能的結果(比如缨硝,內(nèi)存屏障的維基百科條目)摩钙。為了使用一個內(nèi)存屏障,你只要在你代碼里面需要的地方簡單的調(diào)用OSMemoryBarrier函數(shù)查辩。

Volatile 變量適用于獨立變量的另一個內(nèi)存限制類型胖笛。編譯器優(yōu)化代碼通過加載這些變量的值進入寄存器。對于本地變量宜岛,這通常不會有什么問題长踊。但是如果一個變量對另外一個線程可見,那么這種優(yōu)化可能會阻止其他線程發(fā)現(xiàn)變量的任何變化萍倡。在變量之前加上關鍵字volatile可以強制編譯器每次使用變量的時候都從內(nèi)存里面加載身弊。如果一個變量的值隨時可能給編譯器無法檢測的外部源更改,那么你可以把該變量聲明為volatile變量列敲。

因為內(nèi)存屏障和volatile變量降低了編譯器可執(zhí)行的優(yōu)化阱佛,因此你應該謹慎使用它們,只在有需要的地方時候戴而,以確保正確性瘫絮。

3.鎖
  • Mutex(互斥鎖)

一個互斥鎖對于資源來說很像是一個保護性的barrier。它是一種信號量機制填硕,在同一時間只允許一個進程來訪問資源。如果一個互斥鎖正在被一個線程獲取使用,另外一個線程如果想要使用的話就必須等待holder線程釋放這個鎖扁眯。多個一期請求的時候也只會有一個被賦予權限壮莹。

  • Recursive lock(遞歸鎖)

遞歸鎖其實是互斥鎖的一個變種。就是一個線程可以多次持有一個鎖姻檀,其它線程像訪問的時候命满,這個線程必須把這個多次持有都釋放了。應用場景是多個方法绣版,每個都要單獨獲取鎖胶台。

  • Read-write lock(讀寫鎖)

共享互斥鎖。這個在客戶端和服務端有不同杂抽,對服務端而言诈唬,一個連接或者請求就是一個并發(fā)操作,而客戶端缩麸,因為只有一個人铸磅,并發(fā)操作多指一個程序進程內(nèi)的多個場景。就是多個讀操作可以一起整杭朱,而寫操作就必須等所有讀操作都完了阅仔。共享,并互斥弧械。只有POSIX threads才支持八酒。

  • Distributed lock(分布鎖)

提供了process級別的互斥access。它不會真的把process鎖住刃唐。只是提個建議羞迷,告訴process自己最近很忙,要不要停一停唁桩。

  • Spin lock(自旋鎖)

它會反復poll自己的lock conditon闭树,直到lock conditon 變成 true。多是設計多核心應用切換時候用的荒澡。

  • Double-checked lock(雙重檢查鎖)

來回監(jiān)測报辱,不安全,系統(tǒng)不提供

4.條件

條件是信號量的另外一個形式单山,它允許在條件為真的時候線程間互相發(fā)送信號。條件通常被使用來說明資源可用性米奸,或用來確保任務以特定的順序執(zhí)行昼接。當一個線程測試一個條件時悴晰,它會被阻塞直到條件為真。它會一直阻塞直到其他線程顯式的修改信號量的狀態(tài)泪喊。條件和互斥鎖(mutex lock)的區(qū)別在于多個線程被允許同時訪問一個條件袒啼。條件更多是允許不同線程根據(jù)一些指定的標準通過的守門人蚓再。

一個方式是你使用條件來管理掛起事件的池包各。事件隊列可能使用條件變量來給等待線程發(fā)送信號摘仅,此時它們在事件隊列中的時候。如果一個事件到達時髓棋,隊列將給條件發(fā)送合適信號实檀。如果一個線程已經(jīng)處于等待,它會被喚醒按声,屆時它將會取出事件并處理它膳犹。如果兩個事件到達隊列的時間大致相同,隊列將會發(fā)送兩次信號喚醒兩個線程签则。

系統(tǒng)通過幾個不同的技術來支持條件须床。

5.執(zhí)行slector

Cocoa程序包含了一個在一個線程以同步的方式傳遞消息的方便方法。NSObject類聲明方法來在應用的一個活動線程上面執(zhí)行selector的方法渐裂。這些方法允許你的線程以異步的方式來傳遞消息豺旬,以確保它們在同一個線程上面執(zhí)行是同步的。比如柒凉,你可以通過執(zhí)行selector消息來把一個從你分布計算的結果傳遞給你的應用的主線程或其他目標線程族阅。每個執(zhí)行selector的請求都會被放入一個目標線程的run loop的隊列里面,然后請求會按照它們到達的順序被目標線程有序的處理膝捞。

同步的成本

同步幫助確保你代碼的正確性坦刀,但同時將會犧牲部分性能。甚至在無競態(tài)的情況下蔬咬,同步工具的使用將在后面介紹鲤遥。鎖和原子操作通常包含了內(nèi)存屏障和內(nèi)核級別同步的使用來確保代碼正確被保護。如果林艘,發(fā)生鎖的爭奪盖奈,你的線程有可能進入阻塞,在體驗上會產(chǎn)生更大的遲延狐援。

  • mutex獲得時間(0.2ms)

這個時間是沒有競爭條件下的钢坦。如果lock被另一個線程持有究孕,時間就更長了。

  • Atomic compare-and-swap(0.05)

如何進行同步(注意事項)

  • 當心死鎖和活鎖

死鎖:當兩個不同的線程分別保持一個鎖(而該鎖是另外一個線程需要的)又試圖獲得另外線程保持的鎖時就會發(fā)生死鎖场钉。結果是每個線程都會進入持久性阻塞狀態(tài)蚊俺,因為它永遠不可能獲得另外那個鎖。

活鎖:當兩個線程競爭同一個資源的時候就可能發(fā)生活鎖逛万。在發(fā)生活鎖的情況里,一個線程放棄它的第一個鎖并試圖獲得第二個鎖批钠。一旦它獲得第二個鎖宇植,它返回并試圖再次獲得一個鎖。線程就會被鎖起來埋心,因為它花費所有的時間來釋放一個鎖指郁,并試圖獲取其他鎖,而不做實際的工作拷呆。

  • 正確使用Volatile變量

如果你已經(jīng)使用了一個互斥鎖來保護一個代碼段闲坎,不要自動假設你需要使用關鍵詞volatile來保護該代碼段的重要的變量。一個互斥鎖包含了內(nèi)存屏障來確保加載和存儲操作是按照正確順序的茬斧。在一個臨界區(qū)添加關鍵字volatile到變量上面會強制每次訪問該變量的時候都要從內(nèi)存里面從加載腰懂。這兩種同步技巧的組合使用在一些特定區(qū)域是必須的,但是同樣會導致顯著的性能損失项秉。如果單獨使用互斥鎖已經(jīng)可以保護變量绣溜,那么忽略關鍵字volatile。

為了避免使用互斥鎖而不使用volatile變量同樣很重要娄蔼。通常情況下怖喻,互斥鎖和其他同步機制是比volatile變量更好的方式來保護數(shù)據(jù)結構的完整性。關鍵字volatile只是確保從內(nèi)存加載變量而不是使用寄存器里面的變量岁诉。它不保證你代碼訪問變量是正確的锚沸。

  • 使用NSLock或相關協(xié)議類

互斥鎖要注意的是同一個鎖對象,被多個線程獲取的時候涕癣,多個線程都需要等待釋放哗蜈,才能分配執(zhí)行。@synchorize其實是和NSLock一樣的東西属划,獲取了一個對象相關連的鎖恬叹, 但是編譯階段優(yōu)化回去還是個mutex。當一個線程想要多次獲得一個鎖對象的時候要用遞歸鎖同眯,要不就deadlock绽昼,大家可以挑一個。

  • @synchorize

功能上像個語法糖须蜗。使用起來很簡單硅确。但是有這么個過程目溉,就是作為一種預防措施,@synchronized塊隱式的添加一個異常處理例程來保護代碼菱农。該處理例程會在異常拋出的時候自動的釋放互斥鎖缭付。這意味著為了使用@synchronized指令,你必須在你的代碼中啟用異常處理循未。了如果你不想讓隱式的異常處理例程帶來額外的開銷陷猫,你應該考慮使用鎖的類。

  • 使用條件

下篇有個簡單的例子

  • 信號量機制

邏輯上是個PV操作可控制的值的妖,具體使用就很多了绣檬。希望有機會補上。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末嫂粟,一起剝皮案震驚了整個濱河市娇未,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌星虹,老刑警劉巖零抬,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異宽涌,居然都是意外死亡平夜,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進店門护糖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來褥芒,“玉大人,你說我怎么就攤上這事嫡良∶谭觯” “怎么了?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵寝受,是天一觀的道長坷牛。 經(jīng)常有香客問我,道長很澄,這世上最難降的妖魔是什么京闰? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮甩苛,結果婚禮上蹂楣,老公的妹妹穿的比我還像新娘。我一直安慰自己讯蒲,他們只是感情好痊土,可當我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著墨林,像睡著了一般赁酝。 火紅的嫁衣襯著肌膚如雪犯祠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天酌呆,我揣著相機與錄音衡载,去河邊找鬼。 笑死隙袁,一個胖子當著我的面吹牛痰娱,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播菩收,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼猜揪,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了坛梁?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤腊凶,失蹤者是張志新(化名)和其女友劉穎划咐,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體钧萍,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡褐缠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了风瘦。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片队魏。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖万搔,靈堂內(nèi)的尸體忽然破棺而出胡桨,到底是詐尸還是另有隱情,我是刑警寧澤瞬雹,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布昧谊,位于F島的核電站,受9級特大地震影響酗捌,放射性物質(zhì)發(fā)生泄漏呢诬。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一胖缤、第九天 我趴在偏房一處隱蔽的房頂上張望尚镰。 院中可真熱鬧,春花似錦哪廓、人聲如沸狗唉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽敞曹。三九已至账月,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間澳迫,已是汗流浹背局齿。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留橄登,地道東北人抓歼。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像拢锹,于是被迫代替她去往敵國和親谣妻。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,452評論 2 348

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

  • 引用自多線程編程指南應用程序里面多個線程的存在引發(fā)了多個執(zhí)行線程安全訪問資源的潛在問題卒稳。兩個線程同時修改同一資源有...
    Mitchell閱讀 1,984評論 1 7
  • Java8張圖 11蹋半、字符串不變性 12、equals()方法充坑、hashCode()方法的區(qū)別 13减江、...
    Miley_MOJIE閱讀 3,696評論 0 11
  • 從三月份找實習到現(xiàn)在,面了一些公司捻爷,掛了不少辈灼,但最終還是拿到小米、百度也榄、阿里巡莹、京東、新浪甜紫、CVTE降宅、樂視家的研發(fā)崗...
    時芥藍閱讀 42,209評論 11 349
  • Java-Review-Note——4.多線程 標簽: JavaStudy PS:本來是分開三篇的,后來想想還是整...
    coder_pig閱讀 1,639評論 2 17
  • 工作中遇到了頭像上傳的壓縮棵介,發(fā)現(xiàn)inSampleSize 相鄰整數(shù)之間壓縮差別太大了钉鸯。比如2和3,前者會壓縮不夠邮辽,...
    安卓小吳閱讀 790評論 0 51