JAVA并發(fā)編程(一):基礎(chǔ)知識


1. 并發(fā)和并行

  • 并發(fā)是指同一個(gè)時(shí)間段內(nèi)多個(gè)任務(wù)同時(shí)都在執(zhí)行报嵌,而單位時(shí)間內(nèi)只有一個(gè)任務(wù)在執(zhí)行阀趴,單個(gè)cpu通過切換線程上下文實(shí)現(xiàn)。
  • 并行是說在單位時(shí)間內(nèi)多個(gè)任務(wù)同時(shí)在不同cpu上執(zhí)行。

2. 并發(fā)的多面性

線程安全性

  • 共享資源可以被多個(gè)線程所持有或者說多個(gè)線程都可以去訪問該資源。
  • 線程安全性是指當(dāng)多個(gè)線程同時(shí)讀寫一個(gè)共享資源并且沒有任何同步措施時(shí)赌髓,導(dǎo)致出現(xiàn)臟數(shù)據(jù)或者其他不可預(yù)見的結(jié)果的問題。
  • 如果多個(gè)線程都只是讀取共享資源催跪,而不去修改锁蠕,那么就不會(huì)存在線程安全問題。

內(nèi)存可見性問題

  • 線程讀寫變量時(shí)操作的是自己工作內(nèi)存(如Ll 或者L2 緩存或者CPU 的寄存器)中的變量懊蒸。
  • 當(dāng)一個(gè)線程操作共享變量時(shí)荣倾, 它首先從主內(nèi)存復(fù)制共享變量到自己的工作內(nèi)存, 然后對工作內(nèi)存里的變量進(jìn)行處理骑丸, 處理完后將變量值更新到主內(nèi)存舌仍。
  • 由于線程可能通過緩存命中讀取到需要的值,我們無法確保執(zhí)行讀操作的線程能適時(shí)地看到其他線程寫入主內(nèi)存的值通危。

指令重排序

  • JAVA允許編譯器和處理器對指令重排序以提高運(yùn)行性能铸豁, 并且只會(huì)對不存在數(shù)據(jù)依賴性的指令重排序。在單線程下重排序可以保證最終執(zhí)行的結(jié)果與程序順序執(zhí)行的結(jié)果一致菊碟。
  • 重排序在多線程下會(huì)導(dǎo)致非預(yù)期的程序執(zhí)行結(jié)果
  • 使用volatile修飾變量避免重排序和內(nèi)存可見性問題节芥。寫volatile 變量時(shí),可以確保volatile 寫之前的操作不會(huì)被編譯器重排序到volatile 寫之后框沟。讀volatile 變量時(shí),可以確保volatile 讀之后的操作不會(huì)被編譯器重排序到volatile讀之前增炭。

3. synchronized

  • synchronized 塊是Java 提供的一種原子性內(nèi)置鎖忍燥,是排他鎖,經(jīng)常被用來實(shí)現(xiàn)原子性操作
  • 線程的執(zhí)行代碼在進(jìn)入synchronized 代碼塊前會(huì)自動(dòng)獲取內(nèi)部鎖隙姿,這時(shí)候其他線程訪問該同步代碼塊時(shí)會(huì)被阻塞掛起梅垄。
  • 拿到內(nèi)部鎖的線程會(huì)在正常退出同步代碼塊或者拋出異常后或者在同步塊內(nèi)調(diào)用了該內(nèi)置鎖資源的wait 系列方法時(shí)釋放該內(nèi)置鎖。
  • synchronized 的使用就會(huì)導(dǎo)致上下文切換输玷。當(dāng)阻塞一個(gè)線程時(shí)队丝,需要從用戶態(tài)切換到內(nèi)核態(tài)執(zhí)行阻塞操作。
  • 保證內(nèi)存可見性:
    進(jìn)入synchronized塊直接從主內(nèi)存中獲取共享變量欲鹏。
    退出synchronized 塊把在synchronized 塊內(nèi)對共享變量的修改刷新到主內(nèi)存机久。

4. volatile

  • 對于解決內(nèi)存可見性問題, Java 提供了一種弱形式的同步volatile赔嚎,該關(guān)鍵字可以確保對一個(gè)變量的更新對其他線程馬上可見膘盖。
  • 當(dāng)一個(gè)變量被聲明為volatile 時(shí)胧弛,線程在寫入變量時(shí)不會(huì)把值緩存在寄存器或者其他地方,而是會(huì)把值刷新回主內(nèi)存侠畔。
  • 當(dāng)其他線程讀取該共享變量時(shí)结缚,會(huì)從主內(nèi)存重新獲取最新值,而不是使用當(dāng)前線程的工作內(nèi)存中的值软棺。
  • synchronized同樣可以解決內(nèi)存可見性問題红竭,但它是獨(dú)占鎖,會(huì)存在線程上下文切換和線程重新調(diào)度的開銷喘落。
  • 使用情況:
    【1】寫入變量值不依賴變量的當(dāng)前值時(shí)(這屬于讀取-計(jì)算-寫入茵宪,volatile 不保證原子性)
    【2】讀寫變量值時(shí)沒有加鎖,加鎖就不需要volatile了揖盘。

5. 鎖

樂觀鎖和悲觀鎖

  • 悲觀鎖指對數(shù)據(jù)被外界修改持保守態(tài)度眉厨,認(rèn)為數(shù)據(jù)很容易就會(huì)被其他線程修改,所以在數(shù)據(jù)被處理前先對數(shù)據(jù)進(jìn)行加鎖兽狭,并在整個(gè)數(shù)據(jù)處理過程中憾股,使數(shù)據(jù)處于鎖定狀態(tài)。在數(shù)據(jù)庫中箕慧,在對數(shù)據(jù)記錄操作前給記錄加排它鎖服球。如果獲取鎖失敗, 則說明數(shù)據(jù)正在被其他線程修改颠焦, 當(dāng)前線程則等待或者拋出異常斩熊。如果獲取鎖成功,則對記錄進(jìn)行操作伐庭,然后提交事務(wù)后釋放排它鎖粉渠。
  • 樂觀鎖是相對悲觀鎖來說的,它認(rèn)為數(shù)據(jù)在一般情況下不會(huì)造成沖突圾另,所以在訪問記錄前不會(huì)加排它鎖霸株,而是在進(jìn)行數(shù)據(jù)提交更新時(shí),才會(huì)正式對數(shù)據(jù)沖突與否進(jìn)行檢測集乔。

公平鎖與非公平鎖(根據(jù)線程獲取鎖的搶占機(jī)制):

  • 公平鎖表示線程獲取鎖的順序是按照線程請求鎖的時(shí)間早晚來決定的
    ReentrantLock pairLock =new ReentrantLock(true)
  • 非公平鎖則是先來不一定先得去件。ReentrantLock默認(rèn)構(gòu)造函數(shù)是非公平鎖。
  • 在沒有公平性需求的前提下盡量使用非公平鎖扰路,因?yàn)楣芥i會(huì)帶來性能開銷尤溜。

獨(dú)占鎖與共享鎖(根據(jù)鎖只能被單個(gè)線程持有還是能被多個(gè)線程共同持有):

  • 獨(dú)占鎖保證任何時(shí)候都只有一個(gè)線程能得到鎖,如ReentrantLock汗唱。
    獨(dú)占鎖是一種悲觀鎖宫莱,這限制了并發(fā)性,因?yàn)樽x操作并不會(huì)影響數(shù)據(jù)的一致性
  • 共享鎖則可以同時(shí)由多個(gè)線程持有哩罪,例如ReadWriteLock 讀寫鎖梢睛,它允許一個(gè)資源可以被多線程同時(shí)進(jìn)行讀操作肥印。
    共享鎖是一種樂觀鎖

可重入鎖

  • 當(dāng)一個(gè)線程再次獲取它自己已經(jīng)獲取的鎖時(shí)如果不被阻塞,那么我們說該鎖是可重入的绝葡。
  • synchronized 內(nèi)部鎖是可重入鎖
  • 原理是在鎖內(nèi)部維護(hù)一個(gè)線程標(biāo)示深碱,用來標(biāo)示該鎖目前被哪個(gè)線程占用,然后關(guān)聯(lián)一個(gè)計(jì)數(shù)器藏畅。一開始計(jì)數(shù)器值為0,說明該鎖沒有被任何線程占用敷硅。當(dāng)一個(gè)錢程獲取了該鎖時(shí),計(jì)數(shù)器的值會(huì)變成1愉阎,當(dāng)獲取了該鎖的線程再次獲取鎖時(shí)發(fā)現(xiàn)鎖擁有者是自己绞蹦,就會(huì)把計(jì)數(shù)器值加+1,當(dāng)釋放鎖后計(jì)數(shù)器值-1 。當(dāng)計(jì)數(shù)器值為0 時(shí)鎖里面的線程標(biāo)示被重置為null榜旦。此時(shí)喚醒其他被阻塞的線程來競爭鎖幽七。

自旋鎖

  • 當(dāng)一個(gè)線程在獲取鎖(比如獨(dú)占鎖)失敗后,會(huì)被切換到內(nèi)核態(tài)而被掛起溅呢。當(dāng)該線程獲取到鎖時(shí)又需要將其切換到內(nèi)核狀態(tài)而喚醒該線程澡屡。這帶來了開銷。
  • 自旋鎖使用CPU 時(shí)間換取線程阻塞與調(diào)度的開銷咐旧,當(dāng)前線程在獲取鎖時(shí)驶鹉,如果發(fā)現(xiàn)鎖已經(jīng)被其他線程占有,它不馬上阻塞自己铣墨,在不放棄CPU 使用權(quán)的情況下室埋,多次嘗試獲取(默認(rèn)次數(shù)是10 伊约,可以使用-XX:PreBlockSpinsh 參數(shù)設(shè)置)姚淆,直到達(dá)到最大次數(shù)才掛起或獲取到鎖。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末屡律,一起剝皮案震驚了整個(gè)濱河市腌逢,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌疹尾,老刑警劉巖上忍,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件骤肛,死亡現(xiàn)場離奇詭異纳本,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)腋颠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進(jìn)店門繁成,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人淑玫,你說我怎么就攤上這事巾腕∶婢Γ” “怎么了?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵尊搬,是天一觀的道長叁鉴。 經(jīng)常有香客問我,道長佛寿,這世上最難降的妖魔是什么幌墓? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮冀泻,結(jié)果婚禮上常侣,老公的妹妹穿的比我還像新娘。我一直安慰自己弹渔,他們只是感情好胳施,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著肢专,像睡著了一般舞肆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鸟召,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天胆绊,我揣著相機(jī)與錄音,去河邊找鬼欧募。 笑死压状,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的跟继。 我是一名探鬼主播种冬,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼舔糖!你這毒婦竟也來了娱两?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤金吗,失蹤者是張志新(化名)和其女友劉穎十兢,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體摇庙,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡旱物,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了卫袒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宵呛。...
    茶點(diǎn)故事閱讀 38,650評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖夕凝,靈堂內(nèi)的尸體忽然破棺而出宝穗,到底是詐尸還是另有隱情户秤,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布逮矛,位于F島的核電站鸡号,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏须鼎。R本人自食惡果不足惜膜蠢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望莉兰。 院中可真熱鬧挑围,春花似錦、人聲如沸糖荒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽捶朵。三九已至蜘矢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間综看,已是汗流浹背品腹。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留红碑,地道東北人舞吭。 一個(gè)月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像析珊,于是被迫代替她去往敵國和親羡鸥。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評論 2 349

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