java - AtomicInteger 的CAS 问题
问题描述
public final int incrementAndGet() {for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next))return next;} }
这是自增操作,定义: CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做预期值是next吗? 内存值是current?假如1个线程自增时没有其他线程竞争,那么预期值应该比内存值大1啊,怎么会预期值和内存值相同?
问题解答
回答1:泻药~可能题主这里理解有点偏差
current是预期值,不是内存值
next是修改的新值不是预期值
方法compareAndSet的源码就可以看得出来,里面注释已经很明白了
/** * Atomically sets the value to the given updated value * if the current value {@code ==} the expected value. * * @param expect the expected value * @param update the new value * @return {@code true} if successful. False return indicates that * the actual value was not equal to the expected value. */ public final boolean compareAndSet(int expect, int update) {return unsafe.compareAndSwapInt(this, valueOffset, expect, update); }
CAS的操作是按照题主所说,用预期值和内存值比较,只有当相等时,才会把新值写入,否则会不断重试,是一种乐观的态度,而真正的内存值其实是AtomicInteger.value这个属性(其实最关键也不是这个属性,只是个引用而已,真正的boss后面会提到),注意这个value的有关键字volatile修饰
private volatile int value;
所以这个value值其实是一个共享变量,代表着这个变量的可见性,也就是线程之间的可见性,
=======================话多随便扯了哈可见性,不喜可以直接略过================================
简单点说,Java内存模型规定了变量是存在主存中(类似物理内存)的,各个线程都有自己的工作缓存,在对某个变量操作时,不是直接修改主存中的值,而是在自己的工作缓存中执行,最后在同步到主存中,并且线程相互之间的是不能访问对方的工作缓存的
这里说到的可见性,就是指,线程在操作有关键字volatile修饰的变量时,当成功修改了这个变量并写入了主存,那么其他线程的工作缓存中的变量会失效,所以此时其他线程再次去读取变量时会直接从主存中去读,而不会再用自己工作缓存中的值了
==========================================扯完==============================================
刚才说到AtomicInteger.value这个属性对于数据本身而言,只是一个引用,在调用compareAndSet方法时,可以注意到第二个参数,valueOffset,其实这才是关键...真正的Boss,真正的内存的值,因为涉及到在java语言里很少听到的一个词,指针,这个valueOffset其实就是对象内的偏移量啦,这才是真正的内存值
(之所以这个方法compareAndSet里调用的是Unsafe类的方法,Unsafe这其实就是封装了一些类似指针的操作,指针才不安全嘛)
相关文章:
1. docker images显示的镜像过多,狗眼被亮瞎了,怎么办?2. 如何解决Centos下Docker服务启动无响应,且输入docker命令无响应?3. Docker for Mac 创建的dnsmasq容器连不上/不工作的问题4. 请问“由于 Cookie “PHPSESSID”的“SameSite”属性设置为“None”,但缺少“Secure”属性,此 Cookie 未来将被拒绝。”请问出现这个问题怎么办?5. docker网络端口映射,没有方便点的操作方法么?6. docker容器呢SSH为什么连不通呢?7. docker api 开发的端口怎么获取?8. 前端 - 类到底该如何去命名 .newsList 这种的命名难道真的不是过度语义化吗?~9. golang - 用IDE看docker源码时的小问题10. docker start -a dockername 老是卡住,什么情况?

网公网安备