認爲每次獲取數據的時候數據必定會被人修改,因此它在獲取數據的時候會把操做的數據給鎖住,這樣一來就只有它本身可以操做,其餘人都堵塞在那裏。java
認爲每次獲取數據的時候數據不會被別人修改,因此獲取數據的時候並無鎖住整個數據,可是在更新的時候它會去判斷一下要更新的數據有沒有被別人修改過,例如更新前查詢該數據的版本號,更新的時候看看該版本號有沒有被人修改過,若是被人修改過了,那就不會去更新。算法
悲觀鎖:
由於悲觀鎖會鎖住數據,讓其餘人都等待,因此當一個系統併發量不大,並且能夠接收必定延遲的時候能夠選擇悲觀鎖。
樂觀鎖:
由於樂觀鎖會在更新前去查數據,因此比較適合讀多少寫的場景,由於寫操做多的話會形成大量的查詢操做,給系統帶來壓力。例如SVN、Git等版本控制管理器就是應用的樂觀鎖,當你提交數據的時候對比下版本號,若是遠程倉庫的版本號和本地的不同就表示有人已經提交過代碼了,你須要先更新代碼到本地處理一下版本衝突問題,否則是沒有辦法提交的。數據庫
CAS是Compare And Set的縮寫,中文意思就是比較和操做,是一個非阻塞算法。它實際上是一個CPU的指令,它會拿內存值和一個給定的值進行比較,若是相等的話就會把內存值更新爲另外一個給定的值。其實CAS就是使用一個樂觀鎖的機制。安全
從JDK1.5開始java.util.concurrent.atomic包中新增了一些原子類,AtomicInteger、AtomicLong等等,就是專門解決高併發下的同步問題。由於相似i++、++i的操做不是線程安全的,之前咱們都會使用Synchronized關鍵字,可是如今咱們直接使用這些原子類就能夠解決線程安全的問題。下面用代碼來看看有什麼變化。併發
class Test1 { private volatile int count = 0; public synchronized void increment() { //加鎖才能保證線程安全 count++; } public int getCount() { return count; } } class Test2 { private AtomicInteger count = new AtomicInteger(); //使用AtomicInteger以後,不加鎖,也是線程安全的。 public void increment() { count.incrementAndGet(); } public int getCount() { return count.get(); } }
下面這些是AtomicInteger提供的別的方法。高併發
//獲取當前的值 public final int get() //獲取當前的值,並設置新的值 public final int getAndSet(int newValue) //獲取當前的值,並自增 public final int getAndIncrement() //獲取當前的值,並自減 public final int getAndDecrement() //獲取當前的值,並加上預期的值 public final int getAndAdd(int delta)
咱們從源碼的角度看看AtomicInteger是怎麼實現CAS機制的。unsafe是java提供的用來獲取對象內存地址的類,做用是在更新操做時提供「比較並替換」的做用。valueOffset是記錄value自己在內存的地址,value被聲明爲volatile是保證在更新操做時,當前線程能夠拿到value最新的值。this
public class AtomicInteger extends Number implements java.io.Serializable { private static final long serialVersionUID = 6214790243416807050L; // setup to use Unsafe.compareAndSwapInt for updates private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final long valueOffset; static { try { valueOffset = unsafe.objectFieldOffset (AtomicInteger.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } } private volatile int value;
好比incrementAndGet方法,是獲取當前的值並自增。atom
public final int incrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, 1) + 1; }
咱們進getAndAddInt方法看看,getIntVolatile和compareAndSwapInt都是本地方法,就是經過本地方法來實現CAS機制。確保不出現線程安全問題。線程
public final int getAndSetInt(Object var1, long var2, int var4) { int var5; do { var5 = this.getIntVolatile(var1, var2); } while(!this.compareAndSwapInt(var1, var2, var5, var4)); return var5; } public native int getIntVolatile(Object var1, long var2); public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);