Error[8]: Undefined offset: 9, File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 121
File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 473, decode(

ReentrantLock可重入锁(三)CAS原理

CAS大概可以这样描述: 修改变量前先获取变量的值即原值, 修改变量时用原值和变量现在的值比较, 如果相等则把变量改为新值, 多线程同时 *** 作时, 只有一个线程能修改成功.

举个例子: 有个变量a = 0, 现在要把值从0改为1, 过程就是: 用0和变量a比较, 如果相等就把a改为1.

修改变量cpu提供了mov指令(mov 数值, 变量地址), CAS这种先比较再修改cpu提供了cmpxchg指令(cmpxchg 新值, 变量地址), 原值在cmpxchg执行之前放入ax寄存器中.

Java中的CAS

Java的CAS是在Unsafe类的compareAndSwapInt方法中实现的

public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

四个参数

Object var1哪个对象long var2对象的成员属性相对对象的偏移, var1和var2一起确定了要修改的变量的内存地址int var4原值, 修改前的值int var5新值, 要修改成的值

这个是一个native方法, 会调用虚拟机中C++实现的Unsafe_CompareAndSwapInt方法(一般native方法对应的C++方法的方法名为: java类名_java方法名)

Unsafe_CompareAndSwapInt方法

//obj是对象, offset是偏移, e是原值, x是新值
UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x))
  UnsafeWrapper("Unsafe_CompareAndSwapInt");
  oop p = JNIHandles::resolve(obj); //把java对象转成对象首地址
  jint* addr = (jint *) index_oop_from_field_offset_long(p, offset); //用对象的首地址加上偏移算出变量的地址
  return (jint)(Atomic::cmpxchg(x, addr, e)) == e; //cmpxchg实现方法
UNSAFE_END

Atomic::cmpxchg方法, 如果修改成功会返回原值, 否则返回现在变量的值(没成功说明变量的值的不是原值了, 被其他线程修改了)

inline jlong    Atomic::cmpxchg    (jlong    exchange_value, volatile jlong*    dest, jlong    compare_value) {
  bool mp = os::is_MP(); //是不是多处理器
  __asm__ __volatile__ ("cmp 第一个冒号前要执行的汇编指令, %4; je 1f; lock; 1: cmpxchgq %1,(%3)"
                        : "=a" (exchange_value)
                        : "r" (exchange_value), "a" (compare_value), "r" (dest), "r" (mp)
                        : "cc", "memory");
  return exchange_value;
}
//%1寄存器, 里面保存变量exchange_value的值, 新值
//%3寄存器, 里面保存变量dest的值, 变量的内存地址
//%4寄存器, 里面保存变量mp的值, 多处理器标志
//ax寄存器里面是变量compare_value的值, 原值

cmpxchg方法中调用了汇编指令(cmpxchg指令) .

第一个冒号后汇编指令后, 把寄存器ax的值给变量exchange_value第二个冒号后汇编指令前, 把变量exchange_value的值给空闲的寄存器, 把变量compare_value的值给寄存器ax, 把变量dest的值给空闲的寄存器[+++]

第一个冒号后的寄存器为%0, 后面的寄存器一次加1为: %1, %2, ..., 直到第三个冒号前.

lock cmpxchgq %1,(%3); lock前缀保证了指令的原子性, 多线程安全的, (%3)表示寄存器里的值作为内存地址.

cmpxchg r, m  (r表示寄存器, m表示内存地址) 

执行前, ax中会存入原值, r中会存入新值, m是变量地址.

比较ax和m中的值, 相等: 把r里的值更新到m中, 不相等: 只把m里的值更新到ax中.

最后返回的exchange_value如果等于原值表示修改成功.

)
File: /www/wwwroot/outofmemory.cn/tmp/route_read.php, Line: 126, InsideLink()
File: /www/wwwroot/outofmemory.cn/tmp/index.inc.php, Line: 165, include(/www/wwwroot/outofmemory.cn/tmp/route_read.php)
File: /www/wwwroot/outofmemory.cn/index.php, Line: 30, include(/www/wwwroot/outofmemory.cn/tmp/index.inc.php)
ReentrantLock可重入锁(三)CAS原理_随笔_内存溢出

ReentrantLock可重入锁(三)CAS原理

ReentrantLock可重入锁(三)CAS原理,第1张

ReentrantLock可重入锁(三)CAS原理

CAS大概可以这样描述: 修改变量前先获取变量的值即原值, 修改变量时用原值和变量现在的值比较, 如果相等则把变量改为新值, 多线程同时 *** 作时, 只有一个线程能修改成功.

举个例子: 有个变量a = 0, 现在要把值从0改为1, 过程就是: 用0和变量a比较, 如果相等就把a改为1.

修改变量cpu提供了mov指令(mov 数值, 变量地址), CAS这种先比较再修改cpu提供了cmpxchg指令(cmpxchg 新值, 变量地址), 原值在cmpxchg执行之前放入ax寄存器中.

Java中的CAS

Java的CAS是在Unsafe类的compareAndSwapInt方法中实现的

public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

四个参数

Object var1哪个对象long var2对象的成员属性相对对象的偏移, var1和var2一起确定了要修改的变量的内存地址int var4原值, 修改前的值int var5新值, 要修改成的值

这个是一个native方法, 会调用虚拟机中C++实现的Unsafe_CompareAndSwapInt方法(一般native方法对应的C++方法的方法名为: java类名_java方法名)

Unsafe_CompareAndSwapInt方法

//obj是对象, offset是偏移, e是原值, x是新值
UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x))
  UnsafeWrapper("Unsafe_CompareAndSwapInt");
  oop p = JNIHandles::resolve(obj); //把java对象转成对象首地址
  jint* addr = (jint *) index_oop_from_field_offset_long(p, offset); //用对象的首地址加上偏移算出变量的地址
  return (jint)(Atomic::cmpxchg(x, addr, e)) == e; //cmpxchg实现方法
UNSAFE_END

Atomic::cmpxchg方法, 如果修改成功会返回原值, 否则返回现在变量的值(没成功说明变量的值的不是原值了, 被其他线程修改了)

inline jlong    Atomic::cmpxchg    (jlong    exchange_value, volatile jlong*    dest, jlong    compare_value) {
  bool mp = os::is_MP(); //是不是多处理器
  __asm__ __volatile__ ("cmp 第一个冒号前要执行的汇编指令, %4; je 1f; lock; 1: cmpxchgq %1,(%3)"
                        : "=a" (exchange_value)
                        : "r" (exchange_value), "a" (compare_value), "r" (dest), "r" (mp)
                        : "cc", "memory");
  return exchange_value;
}
//%1寄存器, 里面保存变量exchange_value的值, 新值
//%3寄存器, 里面保存变量dest的值, 变量的内存地址
//%4寄存器, 里面保存变量mp的值, 多处理器标志
//ax寄存器里面是变量compare_value的值, 原值

cmpxchg方法中调用了汇编指令(cmpxchg指令) .

第一个冒号后汇编指令后, 把寄存器ax的值给变量exchange_value第二个冒号后汇编指令前, 把变量exchange_value的值给空闲的寄存器, 把变量compare_value的值给寄存器ax, 把变量dest的值给空闲的寄存器

第一个冒号后的寄存器为%0, 后面的寄存器一次加1为: %1, %2, ..., 直到第三个冒号前.

lock cmpxchgq %1,(%3); lock前缀保证了指令的原子性, 多线程安全的, (%3)表示寄存器里的值作为内存地址.

cmpxchg r, m  (r表示寄存器, m表示内存地址) 

执行前, ax中会存入原值, r中会存入新值, m是变量地址.

比较ax和m中的值, 相等: 把r里的值更新到m中, 不相等: 只把m里的值更新到ax中.

最后返回的exchange_value如果等于原值表示修改成功.

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5562590.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-14
下一篇 2022-12-14

发表评论

登录后才能评论

评论列表(0条)

保存