【Java 并发编程】线程锁机制 ( 悲观锁 | 乐观锁 | CAS 三大问题 | ABA 问题 | 循环时间长问题 | 多个共享变量原子性问题 )
文章目錄
- 一、悲觀鎖
- 二、樂(lè)觀鎖
- 三、樂(lè)觀鎖 CAS 三大問(wèn)題
一、悲觀鎖
假設(shè)有 222 個(gè)線程 , 線程 A 和 線程 B ; 線程 A 訪問(wèn)共享資源 , 線程 B 等待 , 一旦線程 A 訪問(wèn)結(jié)束 , 線程 B 訪問(wèn)該共享資源 ;
悲觀鎖 : 只要有 線程 來(lái)操作 共享資源 , 就認(rèn)為肯定 有其它若干線程也要操作該共享資源 , 一定要 對(duì)共享資源進(jìn)行加鎖 ; 任何情況下 , 哪怕 只有一個(gè)線程訪問(wèn)共享資源 , 也要對(duì)該共享資源進(jìn)行加鎖 ; ( 持有悲觀的態(tài)度 )
對(duì)共享資源加鎖 , 會(huì)對(duì)該資源產(chǎn)生負(fù)面影響 , 效率會(huì)降低 ;
如果只是 單線程訪問(wèn)資源 , 不會(huì)產(chǎn)生并發(fā)問(wèn)題 , 沒(méi)有必要進(jìn)行加鎖 ; 如果加了鎖 , 執(zhí)行效率變低 , 造成了資源浪費(fèi) ;
synchronized 就是悲觀鎖 ;
二、樂(lè)觀鎖
樂(lè)觀鎖 : 持有樂(lè)觀的態(tài)度 , 線程 A 訪問(wèn)共享資源 , 樂(lè)觀的認(rèn)為只有 111 個(gè)線程訪問(wèn)該資源 , 不用進(jìn)行加鎖 ;
線程 A 訪問(wèn)主內(nèi)存變量前 , 記錄下值 XXX , 線程 A 訪問(wèn)完畢后 , 會(huì)將最終的值同步到主內(nèi)存中 , 此時(shí)會(huì)檢查下 主內(nèi)存中變量的值是否還是 XXX ,
- 如果是 , 則說(shuō)明 線程 A 訪問(wèn)期間 沒(méi)有線程修改該變量值 , 那么將線程 A 計(jì)算的 新值更新到主內(nèi)存中
- 如果不是 , 主內(nèi)存中的變量值變成了 YYY , 那么說(shuō)明該值 被其它線程修改了 ; 那么將當(dāng)前值拋棄 , 重新從主內(nèi)存獲取變量值 YYY , 然后線程 A 繼續(xù)執(zhí)行 , 執(zhí)行完畢后將計(jì)算結(jié)果同步到主內(nèi)存變量中 , 再次對(duì)比主內(nèi)存中的變量值是否是 YYY , 如果是可以更新 , 如果不是 , 那么再次重復(fù)本操作 ;
樂(lè)觀鎖 , 全程沒(méi)有加鎖 , 沒(méi)有阻塞 , 只要判定主內(nèi)存中被訪問(wèn)的共享變量 , 線程計(jì)算之前的值與計(jì)算之后的值一致 , 就更新到主線程中 ;
三、樂(lè)觀鎖 CAS 三大問(wèn)題
CAS : Compare and Swap , 比較再交換 , 是樂(lè)觀鎖中的線程訪問(wèn)完共享變量后 , 先進(jìn)行變量比較 , 然后在同步共享變量值 ;
JDK 1.51.51.5 之后提供的 java.util.concurrent 包中的類 , 解決了 CAS 相關(guān)問(wèn)題 ;
java.util.concurrent 包簡(jiǎn)稱 J.U.C ;
CAS 解決的 333 大問(wèn)題 :
ABA 問(wèn)題 :
- 問(wèn)題描述 : 線程 A 訪問(wèn)變量 X = 0 , 訪問(wèn)期間 , 線程 B 訪問(wèn) X 將其改為 1 , 然后 線程 C 訪問(wèn) X 將其又改為 0 , 此時(shí)線程 A 訪問(wèn)完畢后 , 查詢發(fā)現(xiàn)變量 X 仍然是 0 , 認(rèn)為期間沒(méi)有線程訪問(wèn)該變量 ;
- 解決方案 : 給變量設(shè)置一個(gè)版本號(hào) , 每次線程訪問(wèn)變量時(shí) , 版本號(hào) +1 , 這樣每次判斷變量的版本號(hào)即可 ;
循環(huán)時(shí)間過(guò)長(zhǎng) :
- 問(wèn)題描述 : 樂(lè)觀鎖中 , 假如連續(xù)多次寫回?cái)?shù)據(jù)時(shí) , 發(fā)現(xiàn)值改變 , 校驗(yàn)失敗 , 導(dǎo)致 重復(fù)執(zhí)行線程代碼 , 會(huì)給 CPU 帶來(lái)很大開(kāi)銷 , 這些 CPU 時(shí)間片都浪費(fèi)了 ;
- 解決方案 : 將鎖升級(jí) ;
保證多個(gè)共享變量原子性問(wèn)題 :
- 問(wèn)題描述 : 針對(duì) 單個(gè)共享變量 訪問(wèn)時(shí) , 使用 atomic 原子類 可以使用 CAS 保證原子操作 , 如果 有多個(gè)共享變量 , CAS 無(wú)法保證操作的原子性 ;
- 解決方案 : 使用 JDK 提供的 AtomicReference 封裝多個(gè)變量到一個(gè)類對(duì)象中 , 保證共享變量的原子性 ;
線程 A 訪問(wèn)共享變量的操作 , 不是原子操作 , 就會(huì)導(dǎo)致如下問(wèn)題 :
線程 A 訪問(wèn)變量 X , 執(zhí)行完畢后 , 變量 X 值原始值進(jìn)行比較 , 比較相等 , 將數(shù)據(jù)更新到主內(nèi)存 , 如果在 比較相等后 , 在 數(shù)據(jù)更新到主內(nèi)存之前 , 有 另外一個(gè)線程 B 修改了該變量 X , 這樣就出現(xiàn)了問(wèn)題 ;
總結(jié)
以上是生活随笔為你收集整理的【Java 并发编程】线程锁机制 ( 悲观锁 | 乐观锁 | CAS 三大问题 | ABA 问题 | 循环时间长问题 | 多个共享变量原子性问题 )的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【BLE MIDI】推荐一个 Andro
- 下一篇: 【Java 并发编程】线程锁机制 ( 锁