最近忙着復習,筆記倒是寫了很多但沒有整理出來,后期抽時間統一上傳
1. CAS
在並發編程下能經常看到CAS,全名Compare and Swap(比較和交換)。是JDK提供的非阻塞原子性操作,它通過硬件保證了比較-交換
這個操作的原子性,主要是處理器級別提供了原子性操作。和重量級鎖(Synchronized)對比,免去了線程上下文切換的開銷,是個不錯的輕量級鎖
實現原理:該方法有四個參數,分別是對象內存位置,對象中變量的偏移量,變量預期值,變量更新值。如果對象obj內存偏移量為offset的變量的值為expect,則使用update替換舊的值expect
2. Unsafe
JDK的Unsafe類提供了一系列的compareAndSwap*方法,下面列出這次用到的方法
- long objectFieldOffet(Field file) 獲取字段的偏移量
- boolean compareAndSwaoInt(Object obj,long offset,int expect,int update) CAS方法
因為Unsafe是個直接操作內存的不安全類,所以JDK規定只有BootStrap類加載器加載的類才能使用Unsafe類,比如rt.jar包下的類就可以。那么我們自定義的使用Application加載器加載的類怎么使用Unsafe呢?答案是:萬能的反射,方法如下
import sun.misc.Unsafe;
import java.lang.reflect.Field;
public class UnsafeUtil {
public static Unsafe getInstance() throws NoSuchFieldException, IllegalAccessException {
// 獲取字段
Field filed = Unsafe.class.getDeclaredField("theUnsafe");
// 設置可訪問
filed.setAccessible(true);
// 返回Unsafe實例
return (Unsafe)filed.get(null);
}
}
注意:使用IDEA方便,而eclipse不能直接導入import sun.misc.Unsafe,需要自行解決
import sun.misc.Unsafe;
import java.lang.reflect.Field;
public class Test {
// 需要CAS修改的字段
private int i = 0;
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
// 獲取Unsafe實例
Unsafe unsafe = UnsafeUtil.getInstance();
// 獲取字段 i 的偏移量
Test test = new Test();
Field field = test.getClass().getDeclaredField("i");
long offset = unsafe.objectFieldOffset(field);
// CAS修改,返回布爾值
boolean isSuccess = unsafe.compareAndSwapInt(test,offset,0,1);
// 打印
System.out.println(isSuccess);
System.out.println(test.getI());
}
}
打印
true
1
《Java並發編程之美》