java開發中進行併發編程時針對操做同一塊區域時,若是不加鎖會出現併發問題,數據不是本身預計獲得的值。我以爲有點像mysql事務中髒讀、不可重複讀、幻讀的問題。加鎖的目的是爲了保證同一時間只有我一我的操做同一個資源。java
jdk提供給了咱們不少鎖的實現方式,用於各類狀況鎖的使用:mysql
public class SynchronizedDemo {
public static void main(String[] args) {
Object o = new Object();
synchronized (o){
System.out.println("ReentrantLockDemo");
}
}
}
複製代碼
ReentrantLock是怎麼實現鎖的機制呢? 經過繼承AbstractQueuedLongSynchronizer(AQS)來進行鎖的,實現原理是AQS中有一個變量來控制是否獲取到了鎖,經過Unsafe的CAS操做來獲取鎖,從而保證線程安全。sql
那麼問題來了?CAS操做的ABA問題如何解決? concurrent包中有提供AtomicStampedReference來解決ABA問題,也就是在CAS操做的同時須要再增長版本的判斷,從而保證不出現ABA的問題。編程
public class SolveCAS {
// 主內存共享變量,初始值爲1,版本號爲1
private static AtomicStampedReference<Integer> atomicStampedReference = new
AtomicStampedReference<>(1, 1);
public static void main(String[] args) {
// t1,指望將1改成10
new Thread(() -> {
// 第一次拿到的時間戳
int stamp = atomicStampedReference.getStamp();
System.out.println(Thread.currentThread().getName()+" 第1次時間戳:"+stamp+" 值爲:"+atomicStampedReference.getReference());
// 休眠5s,確保t2執行完ABA操做
try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); }
// t2將時間戳改成了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()+" 當前最新時間戳:"+atomicStampedReference.getStamp()+" 最新值爲:"+atomicStampedReference.getReference());
},"t1").start();
// t2進行ABA操做
new Thread(() -> {
// 第一次拿到的時間戳
int stamp = atomicStampedReference.getStamp();
System.out.println(Thread.currentThread().getName()+" 第1次時間戳:"+stamp+" 值爲:"+atomicStampedReference.getReference());
// 休眠,修改前確保t1也拿到一樣的副本,初始值爲1
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
// 將副本改成20,再寫入,緊接着又改成1,寫入,每次提高一個時間戳,中間t1沒介入
atomicStampedReference.compareAndSet(1, 20, stamp, stamp + 1);
System.out.println(Thread.currentThread().getName()+" 第2次時間戳:"+atomicStampedReference.getStamp()+" 值爲:"+atomicStampedReference.getReference());
atomicStampedReference.compareAndSet(20, 1, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);
System.out.println(Thread.currentThread().getName()+" 第3次時間戳:"+atomicStampedReference.getStamp()+" 值爲:"+atomicStampedReference.getReference());
},"t2").start();
}
}
複製代碼
使用場景不一樣安全
ReadWriteLock可使用在讀多寫少的狀況,儘可能提高併發的能力 ReadWriteLock、synchronized使用的是獨佔鎖,可是jdk對synchronized在編譯時會有優化。bash