•處理併發問題•我認爲V的值應該是A,若是是的話我就把它修改爲B,若是不是A,那麼說明A被人修改過了,那我就不修改了,避免多人同時修改形成錯誤,• CAS有3個操做數,內存值V,預期值A,要修改的值B,當且僅預期值A和內存值V相同時,纔將內存值修改成B,不然什麼都不作,最後返回如今的V值CAS算法理解java
(1)與鎖索引,使用比較交換(至少簡稱CAS)看上去程序看起來更加複雜一些。但因爲其非附加性,它對死鎖問題天生免疫,而且,線程間的相互影響也遠遠超過比基於鎖的方式要小的。更加劇要的是,使用無鎖的方式徹底沒有鎖競爭帶來的系統開銷,也沒有線程間可轉換調度帶來的開銷,所以,它要比基於鎖的方式擁有更優越的性能。算法
(2)無鎖的好處:數據結構
第一,在高併發的狀況下,它比有鎖的程序擁有更好的性能;第二,它天生就是死鎖免疫的。併發
就具有這兩個優點,就值得咱們冒險嘗試使用無鎖的併發。app
(3)CAS算法的過程是這樣:它包含三個參數CAS(V,E,N):V表示要更新的變量,E表示預期值,N表示新值。僅當V值等於E值時,纔會將V的值設爲N,若是V值和E值不一樣,則說明已經有其餘線程構成更新,則當前線程什麼都不作。最後,CAS返回當前V的真實值。ide
(4)CAS操做是正確樂觀的態度進行的,它老是認爲本身能夠成功完成操做。當多個線程同時使用CAS操做一個變量時,只有一個會勝出,併成功更新,其他均會失敗。失敗的線程不會被掛起,僅是被告知失敗,而且容許再次嘗試,固然也容許失敗的線程放棄操做。基於這樣的原理,CAS操做即便沒有鎖,也能夠發現其餘線程對當前線程的干擾,並進行適當的處理。高併發
(5)簡單地說,CAS須要你額外賦予一個指望值,也就是你認爲這個變量如今應該是某種子的。若是變量不是你想象的那樣,那說明它已經被別人修改過了。你就從新讀取,再次嘗試修改就行了。工具
(6)在硬件層面,大部分的現代處理器都已經支持原子化的CAS指令。在JDK 5.0之後,虛擬機即可以使用這個指令來實現併發操做和併發數據結構,而且,這種操做在虛擬機中能夠說是無處不在。性能
package com.yxzapp.ready;
public class a implements Runnable{
private volatile int value;
//CAS 原理 比較並替換
public synchronized int compareAndSwap(int expectedValue, int newValue){
int oldValue =value;
if(oldValue == expectedValue){
value = newValue;
}
return value;
}
public static void main(String[] args) throws InterruptedException {
a a = new a();
a.value = 0;
Thread t1 =new Thread(a);
Thread t2 =new Thread(a);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(a.value);
}
@Override
public void run() {
compareAndSwap(0,1);
}
}
小彩蛋 debug 模式選擇線程ui
•樂觀鎖•原子類•併發容器
在Java中原子類如何利用CAS實現原子操做的呢
•AtomicIInteger 加載 Unsafe 工具,用來直接操做內存數據
•Unsafe 底層的操做
•用 Volalatile 修飾value字段,保證可見性••getAddAddInt 方法分析 這也是CAS的底層實現•
CAS存在一個很明顯的問題,即ABA問題。
問題:若是變量V初次讀取的時候是A,而且在準備賦值的時候檢查到它仍然是A,那能說明它的值沒有被其餘線程修改過了嗎?
若是在這段期間曾經被改爲B,而後又改回A,那CAS操做就會誤認爲它歷來沒有被修改過。針對這種狀況,java併發包中提供了一個帶有標記的原子引用類AtomicStampedReference,它能夠經過控制變量值的版原本保證CAS的正確性。也能夠因此版本號,時間戳解決