并發(fā)

66,同步訪問共享的可變數(shù)據(jù)

關(guān)鍵字synchronized可以保證在同一時刻,只有一個線程可以執(zhí)行某一個方法,或者某一個代碼塊。

同步不僅可以阻止一個線程看到對象處于不一致的狀態(tài)中,它還可以保證進(jìn)入同步方法或者同步代碼塊的每個線程,都看到同一個鎖保護(hù)的之前的修改效果。

Volatile 變量可用于提供線程安全,但是只能應(yīng)用于非常有限的一組用例:多個變量之間或者某個變量的當(dāng)前值與修改后值之間沒有約束。對變量的寫操作不依賴于當(dāng)前值,該變量沒有包含在具有其他變量的不變式中。不具有原子性

將可變數(shù)據(jù)控制在單個線程中,不共享可變數(shù)據(jù)。當(dāng)多個線程共享可變數(shù)據(jù)的時候,每個讀或?qū)憯?shù)據(jù)的線程都必須執(zhí)行同步。

但一個線程短時間內(nèi)修改一個數(shù)據(jù)對象,然后與其他線程共享,這是尅接受的,只同步共享對象引用的動作。其他線程只是讀取沒有修改,這種對象事實上是不可變的,將這種對象從一個線程傳遞到其他線程被稱作安全發(fā)布

安全發(fā)布對象方法:可以將它保存在靜態(tài)域中,作為類初始化的一部分;可以將它保存在volatile域,final域或者通過正常鎖定訪問的域中;或者將它放到并發(fā)集合中。

67,避免過度同步

依據(jù)情況不同,過度同步可能會導(dǎo)致性能降低,死鎖,甚至不確定的行為。

為了避免活性失敗和安全性失敗,在一個被同步的方法或代碼塊中,永遠(yuǎn)不要放棄對客戶端的控制。換句話說,在一個被同步的區(qū)域內(nèi)部,不要調(diào)用設(shè)計成要被覆蓋的方法,或者由客戶端以函數(shù)對象的形式提供的方法。

在同步區(qū)域調(diào)用外來方法被稱作“開放調(diào)用”。除了可以避免死鎖之外,開放調(diào)用還可以極大地增加并發(fā)性。

通常,你應(yīng)該在同步區(qū)域內(nèi)做盡量少的工作。

在這個多核的時代多度同步的實際成本并不是指獲得鎖所花費的CPu時間;而是指失去了并行地機會,以及因為需要確保每個核都有一個一致的內(nèi)存視圖而導(dǎo)致的延遲。過度同步的另一項潛在開銷在于,他會限制Vm優(yōu)化代碼的能力。

StringBuffer實例幾乎總是被用于單個線程中,而它們執(zhí)行的卻是內(nèi)部同步。為此,StringBuffer基本都由StringBuilder代替。

如果一個可變類要并發(fā)使用,應(yīng)該使這個類編程線程安全的,通過內(nèi)部同步,你還可以獲得,明顯比外部鎖定整個對象更高的并發(fā)性。否則,就不要在內(nèi)部同步。讓客戶在必要的時候從外部同步。

68,executor和task優(yōu)先于線程
  • 如果編寫的是小程序,或者輕載的服務(wù)器,使用Executor.newCachedThreadPool通常是個不錯的選擇。
  • 在大負(fù)載的服務(wù)器中,最好使用Executor.newFixedThreadPool,它為你提供了一個包含固定線程數(shù)目的線程池,或者為了最大限度的控制它,就直接使用ThreadPoolExecutor類。

你不僅應(yīng)該盡量不要編寫自己的工作隊列,而且還應(yīng)該盡量不直接使用線程。現(xiàn)在的關(guān)鍵抽象不再是Thread了,它以前既充當(dāng)工作單位,又是執(zhí)行機制。工作單位和工作單位是分開的,現(xiàn)在的關(guān)鍵抽象是工作單元,稱作任務(wù)task)。

任務(wù)有兩種:Runnable及其近親Callable(它與Runnable類似,但它會返回值)。執(zhí)行任務(wù)的通用機制是executor service。

Executor FrameWork也有一個可以代替java.util.Timer的東西,即ScheduledThreadPoolExecutor。

Timer只有一個線程來執(zhí)行任務(wù),如果timer唯一的線程拋出未被捕捉的異常,timer就會停止工作。而線程池executor支持多個線程,并且優(yōu)雅的從拋出未受檢異常的任務(wù)中恢復(fù)。

69,并發(fā)工具優(yōu)先于wait和notify

java.util.concurrent中更高級的工具分三類:Executor Framework,并發(fā)集合(Concurrent Collection)以及同步器(Synchronizer)。

并發(fā)集合為標(biāo)準(zhǔn)的集合接口提供了高性能的并發(fā)實現(xiàn),這些實現(xiàn)在內(nèi)部自己管理同步。因此,并發(fā)集合中不可能排除并發(fā)活動;將它鎖定沒有什么作用,只會使程序的速度變慢。

70,線程安全性的文檔化

如果你沒有在一個類的文檔中描述其行為的并發(fā)情況,使用這個類的程序員將不得不做出某些假設(shè)。如果這些假設(shè)是錯誤的,這樣得到的程序就可能缺少足夠的同步,或者過度同步。無論屬于哪種情況,都可能會發(fā)生嚴(yán)重的錯誤。

一個類為了可被多個線程安全使用,必須在文檔中清楚地說明它所支持的線程安全性級別。

  • 不可變的——這個類的實例是不可變的。這樣的例子包括String,Long,BigInteger。
  • 無條件的線程安全——這個類的實例是可變的,但是這個類有足夠的內(nèi)部同步。例子包括Random,ConconcurrentHashMap。
  • 有條件的線程安全——除了有些方法為進(jìn)行安全的并發(fā)使用而需要外部同步之外,這種線程安全級別與無條件安全相同。例子包括:Collections.synhronized包裝返回的集合,它們的迭代器要求外部同步。
  • 非線程安全——這個類的實例是可變的。為了并發(fā)使用它們,客戶必須利用自己選擇的外部同步包圍每個方法調(diào)用。例子包括ArrayList
  • 線程對立的——這個類不能安全地被多個線程并發(fā)使用,即使所有的方法調(diào)用都被外圍同步包圍。

類的線程安全說明通常放在它的文檔中,但帶有特殊線程安全屬性的方法則應(yīng)該在它們自己的文檔注釋中說明它們的屬性。

私有鎖只能用在無條件的線程安全類上。私有鎖對象模式特別適用于那些專門為繼承而設(shè)計的類。如果這種類適用它的實例作為鎖的對象,子類可能很容易在無意中妨礙基類的操作,反之亦然。

61,慎用延遲初始化

延遲初始化是延遲到需要域的值時才將它初始化的這種行為。

對于延遲初始化,最好建議“除非絕對必要,否則就不要那么做”。延遲化降低了初始化類或者創(chuàng)建實例的開銷,卻增加了訪問被延遲初始化的域的開銷。

如果域只是在類的實例部分被訪問,并且初始化這個域的開銷很高,可能就值得進(jìn)行延遲初始化。

  • 如果出于性能的考慮而需要對靜態(tài)域使用延遲初始化,就使用lazy initialization holder class 模式。保證在被用時初始化。
  • 如果出于性能的考慮而需要對實例域使用延遲初始化,就使用雙重檢查模式。這種模式避免了在域被初始化之后訪問這個域時的鎖定開銷。

第一次檢查時沒有鎖定,看看這個域是否被初始化;第二次檢查時又鎖定。只有當(dāng)?shù)诙螜z查時標(biāo)明這個域沒有被初始化,才進(jìn)行初始化。如果域已經(jīng)被初始化就不會有鎖定,域被聲明為volatile很重要。

72,不要依賴于線程調(diào)度器

當(dāng)有多個線程可以運行時,由線程調(diào)度器決定哪些線程將會運行,以及運行多長時間。

任何依賴于線程調(diào)度器來達(dá)到正確性或者性能要求的程序,很有可能都是不可移植的。

要編寫健壯,響應(yīng)良好的,可移植的多線程應(yīng)用程序,最好的辦法是確保可運行線程的平均數(shù)量不明顯多于處理器的數(shù)量。

線程優(yōu)先級是java平臺上最不可移植的特征了。

73,避免使用線程組

線程組并沒有提供太多有用的功能,而且他們提供的許多功能還都有缺陷的。

如果你正在設(shè)計的一個類需要處理線程的邏輯組,或許就應(yīng)該使用線程池executor。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,923評論 6 535
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,740評論 3 420
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,856評論 0 380
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,175評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,931評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,321評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,383評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,533評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,082評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,891評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,067評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,618評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,319評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,732評論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,987評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,794評論 3 394
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 48,076評論 2 375

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

  • 一.線程安全性 線程安全是建立在對于對象狀態(tài)訪問操作進(jìn)行管理,特別是對共享的與可變的狀態(tài)的訪問 解釋下上面的話: ...
    黃大大吃不胖閱讀 860評論 0 3
  • Thread機制允許同時進(jìn)行的多個活動,并發(fā)程序設(shè)計比單線程程序設(shè)計要困難得多。 第六十六條、同步訪問共享的可變數(shù)...
    Timorous閱讀 241評論 0 0
  • layout: posttitle: 《Java并發(fā)編程的藝術(shù)》筆記categories: Javaexcerpt...
    xiaogmail閱讀 5,850評論 1 19
  • 曾幾何時,討厭大太陽,干燥又毒辣……幾乎每天都躲在宿舍不敢出門,一出門就打傘,打傘成了我們當(dāng)時出門的習(xí)慣。 其實,...
    躺著仰望天空閱讀 244評論 2 0
  • 今天主要給大家推薦四款用于切圖的工具和一個在線移動圖標(biāo)生成工具,主要的應(yīng)用場景是根據(jù)一張1024*1024的大圖很...
    KODIE閱讀 5,283評論 3 6