自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

CAS 原理深入剖析,深入內(nèi)核源碼的那種

系統(tǒng)
CAS 的意思是 compare and swap,比較并交換。有一種情況是,在你更新結(jié)果之前,其他有個線程在中途把 A 更新成了 5 ,又更新回了 2。但是在當前線程看起來,沒有被改過。這就是 ABA 問題。

 [[385679]]

本文轉(zhuǎn)載自微信公眾號「KK架構(gòu)師」,作者wangkai。轉(zhuǎn)載本文請聯(lián)系KK架構(gòu)師公眾號。   

一、CAS 簡介

CAS 的意思是 compare and swap,比較并交換。

CAS 的示意圖如下:

 

比如一個很簡單的操作,把變量 A = 2 加 1,結(jié)果為 3.

則先讀取 A 的當前值 E 為 2,在內(nèi)存計算結(jié)果 V 為 3,比較之前讀出來的 A 的當前值 2 和 最新值,如果最新值為 2 ,表示這個值沒有被別人改過,則放心的把最終的值更新為 3.

有一種情況是,在你更新結(jié)果之前,其他有個線程在中途把 A 更新成了 5 ,又更新回了 2。但是在當前線程看起來,沒有被改過。這就是 ABA 問題。

二、CAS 的實現(xiàn)

在 java 中,原子類都是用 cas 來實現(xiàn)的,我們可以看一看源碼。

  1. public final int getAndIncrement() { 
  2.     return unsafe.getAndAddInt(this, valueOffset, 1); 

發(fā)現(xiàn)是調(diào)用了 unsafe 類的 getAndAddInt,繼續(xù)看這個方法:

  1. public final int getAndAddInt(Object var1, long var2, int var4) { 
  2.     int var5; 
  3.     do { 
  4.         var5 = this.getIntVolatile(var1, var2); 
  5.     } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4)); 
  6.  
  7.     return var5; 

這里是一個 while 循環(huán),直到比較成功,來看一下這個 compareAndSwapInt 方法

  1. public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5); 

發(fā)現(xiàn)這是一個 native 方法,意味著是 c 或者 c++ 寫的虛擬機的實現(xiàn)。

在網(wǎng)上找到了 HotSpot 虛擬機的源碼,找了一些資料發(fā)現(xiàn)了這個 compareAndSwapInt 的 c++ 代碼:

在 unsafe.cpp 這個文件的 Unsafe_CompareAndSwapInt 這個方法里

 

發(fā)現(xiàn)最終調(diào)用的是 Atomic:: cmpxchg 方法,我們再找到 atomic_linux_x86.inline.hpp 這個文件

 

其中有一句 LOCK_IF_MP(%4) "cmpxchgl %1,(%3)"

LOCK_IF_MP 是一個宏,這個宏的定義是:

 

mp 的意思是 multi processor,意思是在多核 cpu 上,要鎖一下這個指令。

到這里,結(jié)論是,最終調(diào)用了一條匯編指令:lock cmpxchg 指令,來實現(xiàn)底層 cas 的。

也就是 cpu 中有一條 cmpxchg 指令。

但是這條指令不是原子的,也就是拿出來和比較是兩個操作,中間有可能被別人打斷。

所以需要在這個過程加上 lock,意思是,我在對這個內(nèi)存操作的過程中,不允許被別人打斷。

可以簡單理解為把內(nèi)存總線鎖住,別人不允許修改這塊內(nèi)存。

 

三、ABA 問題的解決

很簡單,可以在數(shù)據(jù)上加上版本號即可,改了一次就新增一個版本號。

在 Java 中,可以使用 AtomicStampedReference 來解決這個問題

  1. import java.util.concurrent.atomic.AtomicInteger; 
  2. import java.util.concurrent.atomic.AtomicStampedReference; 
  3.  
  4. public class ABASingle { 
  5.  
  6.     public static void main(String[] args) { 
  7.         AtomicInteger atomicInt = new AtomicInteger(100); 
  8.         atomicInt.compareAndSet(100, 101); 
  9.         atomicInt.compareAndSet(101, 100); 
  10.         System.out.println("new value = " + atomicInt.get()); 
  11.         boolean result1 = atomicInt.compareAndSet(100, 101); 
  12.         System.out.println(result1); // result:true 
  13.  
  14.         AtomicInteger v1 = new AtomicInteger(100); 
  15.         AtomicInteger v2 = new AtomicInteger(101); 
  16.         AtomicStampedReference<AtomicInteger> stampedRef = new AtomicStampedReference<AtomicInteger>( 
  17.                 v1, 0); 
  18.  
  19.         int stamp = stampedRef.getStamp(); 
  20.         stampedRef.compareAndSet(v1, v2, stampedRef.getStamp(), 
  21.                 stampedRef.getStamp() + 1); 
  22.         stampedRef.compareAndSet(v2, v1, stampedRef.getStamp(), 
  23.                 stampedRef.getStamp() + 1); 
  24.         System.out.println("new value = " + stampedRef.getReference()); 
  25.         boolean result2 = stampedRef.compareAndSet(v1, v2, stamp, stamp + 1); 
  26.         System.out.println(result2); // result:false 
  27.     } 

 

責任編輯:武曉燕 來源: KK架構(gòu)師
相關推薦

2020-11-12 18:08:05

JavaLinux多線程

2020-11-20 07:55:55

Linux內(nèi)核映射

2009-03-26 10:33:34

Oracle數(shù)據(jù)塊數(shù)據(jù)庫

2009-03-06 16:48:23

數(shù)據(jù)塊原理Oracle

2016-03-14 16:35:40

IT專家網(wǎng)

2022-11-14 11:09:36

源碼AQS加鎖

2010-09-17 15:32:52

JVM工作原理

2024-04-29 09:06:46

線程初始化源碼

2022-09-05 22:22:00

Stream操作對象

2024-04-29 08:06:19

Redis分布式系統(tǒng)

2010-01-25 17:14:44

Android應用程序

2010-05-25 12:59:00

Subversion

2009-09-14 15:12:40

LINQ to XML

2009-07-06 10:44:45

JSP charset

2009-09-27 17:13:36

Hibernate V

2010-06-03 13:08:51

2011-06-03 13:48:18

JavaScript重構(gòu)

2010-09-15 15:27:06

CSS hack

2023-06-07 07:43:57

數(shù)據(jù)庫JOIN類型

2018-10-31 15:54:47

Java線程池源碼
點贊
收藏

51CTO技術棧公眾號