java并发排它锁_Java并发编程进阶——锁(解析)
一、鎖是什么
java開發(fā)中進(jìn)行并發(fā)編程時(shí)針對(duì)操作同一塊區(qū)域時(shí),如果不加鎖會(huì)出現(xiàn)并發(fā)問題,數(shù)據(jù)不是自己預(yù)計(jì)得到的值。我覺得有點(diǎn)像mysql事務(wù)中臟讀、不可重復(fù)讀、幻讀的問題。加鎖的目的是為了保證同一時(shí)間只有我一個(gè)人操作同一個(gè)資源。
二、如何在代碼里面加鎖
jdk提供給了我們很多鎖的實(shí)現(xiàn)方式,用于各種情況鎖的使用:
三、這些鎖有什么區(qū)別
Ⅰ、實(shí)現(xiàn)原理不同
synchronized是鎖實(shí)現(xiàn)原理是jdk實(shí)現(xiàn)的:
public class SynchronizedDemo {public static void main(String[] args) {Object o = new Object();synchronized (o){System.out.println("ReentrantLockDemo");}} }使用synchronized修飾的代碼會(huì)在編譯時(shí)加上monitorenter、monitorexit進(jìn)行修飾,那么問題來了,為什么用這個(gè)修飾后就能夠保證線程執(zhí)行過程中的安全呢?
因?yàn)閖dk在執(zhí)行monitorenter、monitorexit區(qū)塊的時(shí)候是保證原子性的,要么執(zhí)行完成要么執(zhí)行不完成。synchronized修飾的代碼塊有可視性、原子性、順序性(防止重排序)。
ReentrantLock是怎么實(shí)現(xiàn)鎖的機(jī)制呢?
通過繼承AbstractQueuedLongSynchronizer(AQS)來進(jìn)行鎖的,實(shí)現(xiàn)原理是AQS中有一個(gè)變量來控制是否獲取到了鎖,通過Unsafe的CAS操作來獲取鎖,從而保證線程安全。
那么問題來了?CAS操作的ABA問題如何解決?
concurrent包中有提供AtomicStampedReference來解決ABA問題,也就是在CAS操作的同時(shí)需要再增加版本的判斷,從而保證不出現(xiàn)ABA的問題。
public class SolveCAS {// 主內(nèi)存共享變量,初始值為1,版本號(hào)為1private static AtomicStampedReference<Integer> atomicStampedReference = newAtomicStampedReference<>(1, 1);public static void main(String[] args) {// t1,期望將1改為10new Thread(() -> {// 第一次拿到的時(shí)間戳int stamp = atomicStampedReference.getStamp();System.out.println(Thread.currentThread().getName()+" 第1次時(shí)間戳:"+stamp+" 值為:"+atomicStampedReference.getReference());// 休眠5s,確保t2執(zhí)行完ABA操作try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); }// t2將時(shí)間戳改為了3,cas失敗boolean b = atomicStampedReference.compareAndSet(1, 10, stamp, stamp + 1);System.out.println(Thread.currentThread().getName()+" CAS是否成功:"+b);System.out.println(Thread.currentThread().getName()+" 當(dāng)前最新時(shí)間戳:"+atomicStampedReference.getStamp()+" 最新值為:"+atomicStampedReference.getReference());},"t1").start();// t2進(jìn)行ABA操作new Thread(() -> {// 第一次拿到的時(shí)間戳int stamp = atomicStampedReference.getStamp();System.out.println(Thread.currentThread().getName()+" 第1次時(shí)間戳:"+stamp+" 值為:"+atomicStampedReference.getReference());// 休眠,修改前確保t1也拿到同樣的副本,初始值為1try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }// 將副本改為20,再寫入,緊接著又改為1,寫入,每次提升一個(gè)時(shí)間戳,中間t1沒介入atomicStampedReference.compareAndSet(1, 20, stamp, stamp + 1);System.out.println(Thread.currentThread().getName()+" 第2次時(shí)間戳:"+atomicStampedReference.getStamp()+" 值為:"+atomicStampedReference.getReference());atomicStampedReference.compareAndSet(20, 1, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);System.out.println(Thread.currentThread().getName()+" 第3次時(shí)間戳:"+atomicStampedReference.getStamp()+" 值為:"+atomicStampedReference.getReference());},"t2").start();} }Ⅱ、使用場(chǎng)景不同
ReadWriteLock可以使用在讀多寫少的情況,盡量提升并發(fā)的能力 ReadWriteLock、synchronized使用的是獨(dú)占鎖,但是jdk對(duì)synchronized在編譯時(shí)會(huì)有優(yōu)化。
更多關(guān)于Java的技術(shù)和資訊可以關(guān)注我的專欄:
Java架構(gòu)筑基?zhuanlan.zhihu.com專欄免費(fèi)給大家分享Java架構(gòu)的學(xué)習(xí)資料和視頻
總結(jié)
以上是生活随笔為你收集整理的java并发排它锁_Java并发编程进阶——锁(解析)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ddr读时序波形_测试新体验|如何解决D
- 下一篇: 一场横跨大西洋的实验,开创通讯方式新纪元