在快取領域有一對奇葩,多執行緒的快取和單執行緒的redis,而兩者的效能是差不多的,之所以redis能憑藉單執行緒提供強大的效能並且執行緒安全操作:
一是不存在多執行緒直接切換的資源開銷,
二是大部分的指令都是原子的,原子的指令擁有更高的效率,並且保證執行緒安全!
在java中的原子操作主要封裝在併發包下,以Atomic打頭的類中,如下截圖:
觀察這些類發現,其中的原子操作主要依賴於UnSafe包中類似unsafe.compareAndSwapInt這樣的演算法,取單詞首字母,也即是CAS操作,這也是實現無鎖操作保證執行緒安全的基石,樂觀鎖因為建立在CPU的底層指令原子操作,效率比起同步鎖相當高;
CAS:compare,and,swap:顧名思義,就是比較並交換,這屬於一種樂觀鎖思想,悲觀鎖通常是把共享資源的持有者當做互斥的,由此保證針對共享資源操作的只會是持有鎖的程式!
而樂觀鎖之所以稱為樂觀,就是假設資料在操作之前都是沒有被修改過的,如果已經被修改過,則不進行操作,降低了阻塞的可能性!
CAS的思想在sql操作中常常用到,比如未付款status=1,已付款status=2,sql:update set status=2,version=version+1 where id = xx and status =1 and version=${version},即是如果是還未付款的狀態則付款,如果已經付過款(status=2),則操作失敗;
但是CAS也存在問題:
①,ABA問題,比如上面的sql,如果status是會從1(A)到2(B)再到1(A)的,那麼就會存線上程一已經從1->2->1了,而執行緒二還認為整個資料都沒有變過,繼續修改資料;
②,效能浪費:CAS的操作依賴於自旋(不斷迴圈到滿足條件),如果條件一直不滿足,則CPU開銷一直存在;
下面以AtomicInteger 為例說下CAS的應用類特性:
1,從構造器和get,set方法來看,處理的值需要修飾為記憶體可見的valatile。
2,大多數的方法都是使用了unsafe中的compareAndSwap方法,都是native方法,說明是底層封裝;
直接看案例,如下截圖:
案例中的AtomicInteger,如果改成Integer,結果基本都會小於100,說明資料計算錯誤了!
在快取領域有一對奇葩,多執行緒的快取和單執行緒的redis,而兩者的效能是差不多的,之所以redis能憑藉單執行緒提供強大的效能並且執行緒安全操作:
一是不存在多執行緒直接切換的資源開銷,
二是大部分的指令都是原子的,原子的指令擁有更高的效率,並且保證執行緒安全!
在java中的原子操作主要封裝在併發包下,以Atomic打頭的類中,如下截圖:
觀察這些類發現,其中的原子操作主要依賴於UnSafe包中類似unsafe.compareAndSwapInt這樣的演算法,取單詞首字母,也即是CAS操作,這也是實現無鎖操作保證執行緒安全的基石,樂觀鎖因為建立在CPU的底層指令原子操作,效率比起同步鎖相當高;
CAS:compare,and,swap:顧名思義,就是比較並交換,這屬於一種樂觀鎖思想,悲觀鎖通常是把共享資源的持有者當做互斥的,由此保證針對共享資源操作的只會是持有鎖的程式!
而樂觀鎖之所以稱為樂觀,就是假設資料在操作之前都是沒有被修改過的,如果已經被修改過,則不進行操作,降低了阻塞的可能性!
CAS的思想在sql操作中常常用到,比如未付款status=1,已付款status=2,sql:update set status=2,version=version+1 where id = xx and status =1 and version=${version},即是如果是還未付款的狀態則付款,如果已經付過款(status=2),則操作失敗;
但是CAS也存在問題:
①,ABA問題,比如上面的sql,如果status是會從1(A)到2(B)再到1(A)的,那麼就會存線上程一已經從1->2->1了,而執行緒二還認為整個資料都沒有變過,繼續修改資料;
②,效能浪費:CAS的操作依賴於自旋(不斷迴圈到滿足條件),如果條件一直不滿足,則CPU開銷一直存在;
下面以AtomicInteger 為例說下CAS的應用類特性:
1,從構造器和get,set方法來看,處理的值需要修飾為記憶體可見的valatile。
2,大多數的方法都是使用了unsafe中的compareAndSwap方法,都是native方法,說明是底層封裝;
直接看案例,如下截圖:
案例中的AtomicInteger,如果改成Integer,結果基本都會小於100,說明資料計算錯誤了!