i++是否是线程安全的?为什么?
因为i++ 不是原子性操作 故i++是线程不安全
i++操作分为三步
读取i的值 i加1,
写入i的值 i++是线程不安全的,
多线程i++会造成结果不一致
怎么解决呢? 加锁 JAVA原子类
JAVA原子类
AtomicInteger AtomicInteger位于java.util.concurrent.atomic包下,是对int的封装,提供原子性的访问和更新操作。
Q: AtomicInteger是怎么实现原子性操作的?
A:其原子性操作的实现是基于CAS
Q:CAS是什么?
CAS(compare-and-swap)直译即比较并交换。 CAS的思想很简单:三个参数,一个当前内存值V、旧的预期值A、即将更新的值B,当且仅当预期值A和内存值V相同时,将内存值修改为B并返回true,否则什么都不做,并返false。在JAVA中,CAS通过调用C++库实现,由C++库再去调用CPU指令集。在大多数处理器上 CAS 都是个非常轻量级的操作,这也是其优势所在。
CAS存在的问题
ABA问题
如果某个线程在CAS操作时发现,内存值和预期值都是A,就能确定期间没有线程对值进行修改吗?答案未必,如果期间发生了 A -> B -> A 的更新,仅仅判断数值是 A,可能导致不合理的修改操作。
Q:怎么解决呢? A:加版本号。
针对这种情况,Java 提供了 AtomicStampedReference 和AtomicMarkableReference工具类,通过为引用建立类似版本号的方式,来保证 CAS 的正确性。