jdk 源碼分析(10)java unsafe 分析

jdk裏面原子操作unsafe都是native方法,看不到源代碼,所以特意下載openjdk 9 的版本。

1)獲取unsafe 對象,這個是openjdk裏的方法。通過反射獲得。
  1. static {
  2. Reflection.registerMethodsToFilter(Unsafe.class, "getUnsafe");
  3. }
  1. @CallerSensitive
  2. public static Unsafe getUnsafe() {
  3. Class<?> caller = Reflection.getCallerClass();
  4. if (!VM.isSystemDomainLoader(caller.getClassLoader()))
  5. throw new SecurityException("Unsafe");
  6. return theUnsafe;
  7. }
所以需要使用時直接
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 )

  1. UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSetInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x)) {
  2. oop p = JNIHandles::resolve(obj);
  3. //獲取對象的變量的地址
  4. jint* addr = (jint *)index_oop_from_field_offset_long(p, offset);
  5. //調用Atomic操作
  6. return (jint)(Atomic::cmpxchg(x, addr, e)) == e;
  7. } UNSAFE_END
進入atomic.hpp,大意就是先去獲取一次結果,如果結果和現在不同,就直接返回,因爲有其他人修改了;否則會一直嘗試去修改。直到成功。
  1. inline jbyte Atomic::cmpxchg(jbyte exchange_value, volatile jbyte* dest,
  2. jbyte compare_value, cmpxchg_memory_order order) {
  3. STATIC_ASSERT(sizeof(jbyte) == 1);
  4. volatile jint* dest_int =
  5. static_cast<volatile jint*>(align_ptr_down(dest, sizeof(jint)));
  6. size_t offset = pointer_delta(dest, dest_int, 1);
  7. jint cur = *dest_int;
  8. jbyte* cur_as_bytes = reinterpret_cast<jbyte*>(&cur);
  9. // current value may not be what we are looking for, so force it
  10. // to that value so the initial cmpxchg will fail if it is different
  11. cur_as_bytes[offset] = compare_value;
  12. // always execute a real cmpxchg so that we get the required memory
  13. // barriers even on initial failure
  14. do {
  15. // value to swap in matches current value ...
  16. jint new_value = cur;
  17. // ... except for the one jbyte we want to update
  18. reinterpret_cast<jbyte*>(&new_value)[offset] = exchange_value;
  19. jint res = cmpxchg(new_value, dest_int, cur, order);
  20. if (res == cur) break; // success
  21. // at least one jbyte in the jint changed value, so update
  22. // our view of the current jint
  23. cur = res;
  24. // if our jbyte is still as cur we loop and try again
  25. } while (cur_as_bytes[offset] == compare_value);
  26. return cur_as_bytes[offset];
  27. }



unsafe.cpp 裏面 還包含很多其他的方法的實現,就不再這裏分析了。





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章