博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Unsafe 学习和源码阅读
阅读量:4704 次
发布时间:2019-06-10

本文共 3963 字,大约阅读时间需要 13 分钟。

在代码中获取 Unsafe 对象的方法:

 

// 在 AtomicInteger 里面是这么用的 private static final Unsafe unsafe = Unsafe.getUnsafe();

 

// 获取内存的偏移地址,有点奇怪啊,为啥是获取这个类的,而不是这个对象的呢? static {
try {
valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } }

 

 

1.8 之前 Unsafe 的包路径为:

package sun.misc;

而到了 Java 9,它的包路径改成了下面这个,说明这个类已经开放使用。

package jdk.internal.misc;

 

获取 Unsafe 对象,这个是 openjdk 里的方法,通过反射获得。

static {
Reflection.registerMethodsToFilter(Unsafe.class, "getUnsafe"); }

 

 

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 乐观锁

如果变量没有被其他线程改变的话,会一直尝试去修改变量,直到变成修改值。

CAS,Compare and Swap 即比较并交换,设计并发算法时常用到的一种技术,java.util.concurrent 包全完建立在 CAS 之上,没有 CAS 也就没有此包,可见 CAS 的重要性。

当前的处理器基本都支持 CAS,只不过不同的厂家的实现不一样罢了。CAS 有三个操作数:内存值 V、旧的预期值 A、要修改的值 B,当且仅当预期值 A 和内存值 V 相同时,将内存值修改为 B 并返回 true,否则什么都不做并返回 false。

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

进入 atomic.hpp,大意就是先去获取一次结果,如果结果和现在不同,就直接返回,因为有其他人修改了;否则会一直尝试去修改。直到成功。

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
(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
(&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
(&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]; }

 

5)CAS的缺点

CAS 看起来很美,但这种操作显然无法涵盖并发下的所有场景,并且 CAS 从语义上来说也不是完美的,存在这样一个逻辑漏洞:如果一个变量 V 初次读取的时候是 A 值,并且在准备赋值的时候检查到它仍然是 A 值,那我们就能说明它的值没有被其他线程修改过了吗?如果在这段期间它的值曾经被改成了 B,然后又改回 A,那 CAS 操作就会误认为它从来没有被修改过。这个漏洞称为 CAS 操作的 "ABA" 问题。java.util.concurrent 包为了解决这个问题,提供了一个带有标记的原子引用类 "AtomicStampedReference",它可以通过控制变量值的版本来保证 CAS 的正确性。不过目前来说这个类比较 "鸡肋",大部分情况下 ABA 问题并不会影响程序并发的正确性,如果需要解决 ABA 问题,使用传统的互斥同步可能回避原子类更加高效。

 

转载于:https://www.cnblogs.com/tuhooo/p/10579689.html

你可能感兴趣的文章
CF1202F You Are Given Some Letters...
查看>>
CF1179C Serge and Dining Room
查看>>
CF1168B Good Triple
查看>>
CF1208E Let Them Slide
查看>>
CF1086E Beautiful Matrix
查看>>
在单位上班的25条建议(建议收藏)
查看>>
web前端--http协议
查看>>
欧拉定理证明&阶乘的逆元
查看>>
Prime Game Gym - 101981J(网络流/二分图)
查看>>
Teamwork Gym - 101492E (dp)
查看>>
No Link, Cut Tree! Gym - 101484F(dp)
查看>>
Coprimes Gym - 101492C(bitset)
查看>>
Partial Tree UVALive - 7190(完全背包)
查看>>
『深度应用』NLP机器翻译深度学习实战课程·零(基础概念)
查看>>
『开发技术』Windows极简安装使用face_recognition实现人脸识别
查看>>
『深度应用』NLP命名实体识别(NER)开源实战教程
查看>>
『开发技术』GPU训练加速原理(附KerasGPU训练技巧)
查看>>
『深度应用』NLP机器翻译深度学习实战课程·壹(RNN base)
查看>>
『深度应用』一小时教你上手MaskRCNN·Keras开源实战(Windows&Linux)
查看>>
『王霸之路』从0.1到2.0一文看尽TensorFlow奋斗史
查看>>