4.1节关于compareAndSwapInt()方法的形参解释是不是有问题?
来源:3-1 线程安全性-原子性-atomic-1
![](http://img1.sycdn.imooc.com/user/545864190001966102200220-100-100.jpg)
shinysirius
2018-04-01
4.1节7分54秒左右,讲解CAS方法时
unsafe.compareAndSwapInt(var1, var2, var5, var5 + var4)
解释`var2`是原来的值,var5是底层的值,最后一个形参是更换的值。实现原理是var2与var5进行比较,如果相同则硬件把值置为var5+var4。
但我查看调用:
public final int incrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, 1) + 1; }
发现`var2`是valueOffset,即AtomicInteger中值的地址偏移量,这个值是不会变的。百度查阅资料后发现,正确的流程解释应该是:
`var2`是AtomicInteger的value的相对地址值,`var5`是期望值,`var5 + var4`是置换值,与compareAndSet类似,每次循环调本地方法时,传最新的预期值,和符合修改值。由本地方法中硬件层具体实现,如果预期值和最新值相同,将AtomicInteger对象的value值改为符合修改值
5回答
-
wwpbjing
2018-11-03
尝试班门弄斧地解答:
我最初对于Java语言的理解是:Java无法像C/C++那样使用指针操作内存,
其实Java语言偷偷地埋了个后门:sun.misc.Unsafe(Java9开始计划废弃),
这个类可以完成:
1、分配/重新分配/释放内存,(allocateMemory/reallocateMemory/freeMemory)
2、获得对象中某个属性/静态属性的在该对象中的偏移地址(objectFieldOffset/staticFieldOffset),
3、使用CAS等CPU的操作原语(compareAndSwapObject/compareAndSwapInt/compareAndSwapLong)
4、存取普通变量/volatile变量(putObject/getObject/putObjectVolatile/getObjectVolatile...)
5、线程挂起/恢复(park/unpark...)
6、内存屏障(loadFence/storeFence)
7、synchronized关键字中monitor对象锁定解锁(monitorEnter/monitorExit)
...
这些方法是Java很多底层功能的实现基石
1、NIO直接内存(Direct Memory,参见java.nio.DirectByteBuffer类)
2、大部分Unsafe类中的方法都需要一个类型为long的offset参数:
eg:public native Object getObject(Object obj, long offset); public final native boolean compareAndSwapInt(obj, offset, expect, update);
3、可用于实现基于CAS的乐观锁等操作
4、存取变量/volatile变量
5、java.util.concurrent.locks.LockSupport类中park/unpark系列方法实现的基础,LockSupport又是J.U.C实现的基础,用以实现线程挂起/恢复
6&7、还需要结合JVM才能彻底明白,底层的东西,自己也半吊子,就省略了
再多插一句:
sun.misc.Unsafe类的静态工厂方法比较有意思:public static Unsafe getUnsafe() { Class var0 = Reflection.getCallerClass(); if (!VM.isSystemDomainLoader(var0.getClassLoader())) { throw new SecurityException("Unsafe"); } else { return theUnsafe; } }
getUnsafe方法会验证类加载器,只有启动类加载器加载的类才可以调用Unsafe.getUnsafe方法,
自己写的类由于是应用(系统)类加载器加载的就会抛异常:SecurityException
此举显然是JDK开发者不希望应用开发者调用Unsafe类中的方法,毕竟这个类功能太过强大也太过底层,
使用不当是有很大风险的,当然我们可以使用Java黑魔法————反射拿到Unsafe实例
我提供两种反射思路拿到Unsafe实例:// 获取Unsafe类中属性"theUnsafe"获取实例 try { Field field = Unsafe.class.getDeclaredField("theUnsafe"); field.setAccessible(true); Unsafe unsafe = (Unsafe) field.get(null); System.out.println(unsafe); } catch (NoSuchFieldException | IllegalAccessException e) { e.printStackTrace(); }
// 通过私有构造器创建实例 try { Constructor<Unsafe> c = Unsafe.class.getDeclaredConstructor(); c.setAccessible(true); Unsafe unsafe = c.newInstance(); System.out.println(unsafe); } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) { e.printStackTrace(); }
有了Unsafe实例,我们就可以玩了:
public class CASDemo { private static Unsafe unsafe; private int count = 0; static { try { Field field = Unsafe.class.getDeclaredField("theUnsafe"); field.setAccessible(true); unsafe = (Unsafe) field.get(null); } catch (NoSuchFieldException | IllegalAccessException e) { e.printStackTrace(); } } public static void main(String[] args) throws Exception { CASDemo instance = new CASDemo(); // 使用反射API获取count变量的Field Field countVariableField = CASDemo.class.getDeclaredField("count"); // 使用Unsafe类中objectFieldOffset方法获取CASDemo类中count属性的偏移地址:offset long countVariableAddressOffset = unsafe.objectFieldOffset(countVariableField); System.out.println("CASDemo类中count属性内存偏移地址:" + countVariableAddressOffset); // 我们来玩compareAndSwapInt了 boolean success = unsafe.compareAndSwapInt(instance, countVariableAddressOffset, 0, 1); System.out.println("CAS 成功:" + success); System.out.println("经过CAS,count值变为:" + instance.count); } }
另外对于x86 CPU,CAS实际是一条名为“cmpxchg”的指令,了解即可。
最后希望这个回答你能彻底明白
00 -
birdskyws
2018-07-12
感谢 shinysirius
学习的时候,也卡在这块了,老师没说清楚。看同学的解释大概是什么意思了。把var5交给底层判断,如果var5没变,那么改为var5+var4,即修改为目的结果。
012018-10-12 -
Jimin
2018-04-02
我看了一下视频,把传入的变量当时看错了,因此把var2的值说错了。
借这个问题,再总结一下:
compareAndSwapInt(var1, var2, var5, var5 + var4)换成 compareAndSwapInt(obj, offset, expect, update)能清楚一些,如果obj内的value和expect相等,就证明没有其他线程改变过这个变量,那么就更新它为update,如果这一步CAS没有成功,那就采用自旋的方式继续进行CAS操作。这块是一个CPU指令完成的,依旧是原子操作。
042018-11-13 -
Jimin
2018-04-01
你好,你说的这个没问题,我现在不方便看视频,等我确认一下
00 -
shinysirius
提问者
2018-04-01
这个地方今天看的时候困惑了半天
00
相似问题