jdk 原始碼分析(10)java unsafe 分析
阿新 • • 發佈:2019-01-22
jdk裡面原子操作unsafe都是native方法,看不到原始碼,所以特意下載openjdk 9 的版本。
1)獲取unsafe 物件,這個是openjdk裡的方法。通過反射獲得。
static {
Reflection.registerMethodsToFilter(Unsafe.class,"getUnsafe");
}
@CallerSensitive
public static Unsafe getUnsafe(){
Class<?> caller =Reflection.getCallerClass();
if(!VM.isSystemDomainLoader(caller.getClassLoader()))
throw new SecurityException("Unsafe");
return theUnsafe
}
private static final Unsafe unsafe = Unsafe.getUnsafe();unsafe 物件主要包括1)記憶體管理
public native long allocateMemory(long var1); public native long reallocateMemory(long var1, long var3); public native void setMemory(Object var1, long var2, long var4, byte var6);2)物件cas,這個是樂觀鎖,如果變數沒有被其他執行緒改變的話。會一直嘗試去修改變數。直到變成修改值。等會將分析一下原始碼。c語言的。
public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5); public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5); public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);這裡的引數是,物件,偏移量,期望值,修改值。 獲取偏移量的方法:
valueOffset還有:= unsafe.objectFieldOffset (AtomicBoolean.class.getDeclaredField("value"));
public native long staticFieldOffset(Field var1); public native long objectFieldOffset(Field var1); public native Object staticFieldBase(Field var1);3)supportlock
public native void unpark(Object var1); public native void park(boolean var1, long var2);park類似於wait,unpark類似於notify。 4)cas 原始碼分析 具體見unsafe.cpp (版本: openjdk 9 )
UNSAFE_ENTRY(jboolean,Unsafe_CompareAndSetInt(JNIEnv*env, jobject unsafe, jobject obj, jlong offset, jint e, jint x)){
oop p =JNIHandles::resolve(obj);
//獲取物件的變數的地址
jint* addr =(jint *)index_oop_from_field_offset_long(p, offset);
//呼叫Atomic操作
return(jint)(Atomic::cmpxchg(x, addr, e))== e;
} UNSAFE_END
inline jbyte Atomic::cmpxchg(jbyte exchange_value, volatile jbyte* dest,
jbyte compare_value, cmpxchg_memory_order order){
STATIC_ASSERT(sizeof(jbyte)==1);
volatile jint* dest_int =
static_cast<volatile jint*>(align_ptr_down(dest, sizeof(jint)));
size_t offset = pointer_delta(dest, dest_int,1);
jint cur =*dest_int;
jbyte* cur_as_bytes = reinterpret_cast<jbyte*>(&cur);
// current value may not be what we are looking for, so force it
// to that value so the initial cmpxchg will fail if it is different
cur_as_bytes[offset]= compare_value;
// always execute a real cmpxchg so that we get the required memory
// barriers even on initial failure
do{
// value to swap in matches current value ...
jint new_value = cur;
//... except for the one jbyte we want to update
reinterpret_cast<jbyte*>(&new_value)[offset]= exchange_value;
jint res = cmpxchg(new_value, dest_int, cur, order);
if(res == cur)break;// success
// at least one jbyte in the jint changed value, so update
// our view of the current jint
cur = res;
//if our jbyte is still as cur we loop and try again
}while(cur_as_bytes[offset]== compare_value);
return cur_as_bytes[offset];
}