當線程用synchronize鎖的時候,可以保證線程是具有原子性 可見性 有序性的。
原子性,
表現為每個可以單獨操作,不互相依賴,在線程中表現為每個線程都有所以它自己的一份copy值,不定期的刷新到主內存。(如果有鎖,ulock時刷新到主內存)
而volatile變量不具有原子性,每次讀寫都是自己去主內存讀主內存的值,也真是由於此種原因不能進行計數器操作,例如:
volatile i =1;
線程A,線程B 同時 i++;
i++ 即
i=i; //從主內存中讀 1
i+1; //通過獲取的值。計算 2
i=i+1; //把計算的值寫入主內存中 3
當線程執行順序如下時 A1 – >B1—>A2—>A3—>A1—>B2—>B3, 最后結果導致運行了兩次結果還是2
對此,
1, 可以用CAS算法進行改進
CAS也可成為樂觀鎖,實現原理,通過保存原有值進行比較結果,直到更改成功
實現原理,CAS保存了3個值 H當前值(作為預期值),V內存值,S計算值
代碼實現如下
public final int casTest() {
for (;;) {
int h=i; //A線程叫AH,B線程描述為BH 1
int s = i + 1; // A線程叫AS,B線程描述為BS 2
if(h==i){ // 比較內存值和預期值 3
i=s; // 如果相同,賦值,成功CAS 4
break;
}
}
A1 (A開始時用AH保存內存中此時的i值)->
B1(B開始時也用BH保存當前i值)->
A2 (把計算值2賦給AS)
A3(比較保存的AH和讀取內存值AV,都是等於1,未改變)
A4(所以CAS成功,把AS即2放入內存中)
B2(把計算值2賦給BS)
B3(比較BH和讀取當前內存值BV,BH是1,BV是2,所以不相等,返回到B1)
B1 (故重新取出內存值i,重復計算,此時BH=BV=2,BS=3賦給主內存,完成計數)
其實在並發包中的實現原理我也差不多(待考證……),只是用的是native方法,看代碼
/**
* Atomically sets to the given value and returns the old value.
*
* @param newValue the new value
* @return the previous value
*/
public final int getAndSet(int newValue) {
for (;;) {
int current = get(); // step 1
if (compareAndSet(current, newValue)) //step 2
return current;
}
}
step1 相當於獲取當前值h,並保存
step2 newValue相當於比較s,計算值
2, 當然可以用synchronize鎖進行同步(略)