Atomic

简介: CAS原语 CAS(compare and swap)是一组原语指令,用来实现多线程下的变量同步。 public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); } 在 x86 下的指令CMPXCHG实现了CAS,前置LOCK既可以达到原子性操作。

CAS原语

CAS(compare and swap)是一组原语指令,用来实现多线程下的变量同步。
    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

在 x86 下的指令CMPXCHG实现了CAS,前置LOCK既可以达到原子性操作。截止2013,大部分多核处理器均支持CAS。

CAS原语有三个参数, 内存地址,期望值,新值。如果内存地址的值==期望值,表示该值未修改,此时可以修改成新值。否则表示修改失败,返回false,由用户决定后续操作。
在x86 平台上,CPU提供了在指令执行期间对总线加锁的手段。CPU芯片上 有一条引线#HLOCK pin,如果汇编语言的程序中 在一条指令前面加上前缀"LOCK",经过汇编以后的机器代码就使CPU在执行这条指令的时候 把#HLOCK pin的电位拉低,持续到这条指令结束时放开,从而 把总线锁住,这样同一总线上别的CPU就暂时不能通过总线访问内存了,保证了这条指令在多处理器环境中的原子性。

ABA 问题

AtomicMarkableReference/AtomicStampedReference在解决“ABA问题”上很有用
thread1意图对val=1进行操作变成2,cas(*val,1,2)。
thread1先读取val=1;thread1被抢占(preempted),让thread2运行。
    public final int getAndSet(int newValue) {
        for (;;) {
       //先读取val=1
int current = get();
       //线程被抢占
if (compareAndSet(current, newValue)) return current; } }

thread2 修改val=3,又修改回1。

thread1继续执行,发现期望值与“原值”(其实被修改过了)相同,完成CAS操作。

使用CAS会造成ABA问题,特别是在使用指针操作一些并发数据结构时。
解决方案
ABAʹ:添加额外的标记用来指示是否被修改。 

AtomicIntegerFieldUpdater<T>

AtomicLongFieldUpdater<T>

AtomicReferenceFieldUpdater<T,V>

是基于反射的原子更新字段的值。

相应的API也是非常简单的,但是也是有一些约束的。

(1)字段必须是volatile类型的!volatile到底是个什么东西。

(2)字段的描述类型(修饰符public/protected/default/private)是与调用者与操作对象字段的关系一致。也就是说调用者能够直接操作对象字段,那么就可以反射进行原子操作。但是对于父类的字段,子类是不能直接操作的,尽管子类可以访问父类的字段。

(3)只能是实例变量,不能是类变量,也就是说不能加static关键字。

(4)只能是可修改变量,不能使final变量,因为final的语义就是不可修改。实际上final的语义和volatile是有冲突的,这两个关键字不能同时存在。

(5)对于AtomicIntegerFieldUpdaterAtomicLongFieldUpdater只能修改int/long类型的字段,不能修改其包装类型(Integer/Long)。如果要修改包装类型就需要使用AtomicReferenceFieldUpdater。 

import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;   
  
public class AtomicIntegerFieldUpdaterDemo {   
  
   class DemoData{  
       public volatile int value1 = 1;  
       volatile int value2 = 2;  
       protected volatile int value3 = 3;  
       private volatile int value4 = 4;  
   }  
    AtomicIntegerFieldUpdater<DemoData> getUpdater(String fieldName) {  
        return AtomicIntegerFieldUpdater.newUpdater(DemoData.class, fieldName);  
    }  
    void doit() {  
        DemoData data = new DemoData();  
        System.out.println("1 ==> "+getUpdater("value1").getAndSet(data, 10));  
        System.out.println("3 ==> "+getUpdater("value2").incrementAndGet(data));  
        System.out.println("2 ==> "+getUpdater("value3").decrementAndGet(data));  
        System.out.println("true ==> "+getUpdater("value4").compareAndSet(data, 4, 5));  
    }  
    public static void main(String[] args) {  
        AtomicIntegerFieldUpdaterDemo demo = new AtomicIntegerFieldUpdaterDemo();  
        demo.doit();  
    }  
}   

在上面的例子中DemoData的字段value3/value4对于AtomicIntegerFieldUpdaterDemo类是不可见的,因此通过反射是不能直接修改其值的。

AtomicMarkableReference类描述的一个<Object,Boolean>的对,可以原子的修改Object或者Boolean的值,这种数据结构在一些缓存或者状态描述中比较有用。这种结构在单个或者同时修改Object/Boolean的时候能够有效的提高吞吐量。

 AtomicStampedReference类维护带有整数“标志”的对象引用,可以用原子方式对其进行更新。对比AtomicMarkableReference类的<Object,Boolean>,AtomicStampedReference维护的是一种类似<Object,int>的数据结构,其实就是对对象(引用)的一个并发计数。但是与AtomicInteger不同的是,此数据结构可以携带一个对象引用(Object),并且能够对此对象和计数同时进行原子操作。

 

目录
相关文章
|
4月前
|
算法 搜索推荐 Java
collections.shuffle
`Collections.shuffle()` 是 Java 中用于随机打乱列表顺序的静态方法,基于 Fisher-Yates 算法实现,支持使用默认或自定义随机数生成器,适用于抽奖、游戏、随机抽样等场景,且会直接修改原列表。
174 0
|
3月前
|
Web App开发 缓存 监控
有哪些常用的缓存清除工具?
有哪些常用的缓存清除工具?
502 0
|
5月前
|
数据管理 数据挖掘 API
深入研究:shopee商品列表API接口指南
Shopee 是东南亚和中国台湾地区的跨境电商平台,其开放平台(Shopee Open API)为开发者提供商品数据、店铺管理和订单处理等接口。商品列表 API 为核心功能之一,支持按店铺获取商品列表和搜索平台商品。通过 shop_id 等参数可获取指定店铺商品信息,支持分页与状态筛选;通过关键词、类目 ID 和价格范围等条件可搜索平台商品,适用于构建比价工具和选品分析系统。
|
8月前
|
Oracle 关系型数据库 数据库
【赵渝强老师】Oracle的闪回版本查询
本文介绍了Oracle数据库的闪回版本查询(Flashback Version Query)功能,通过示例详细讲解了其使用方法。闪回版本查询可获取指定时间区间内行的不同版本,利用`versions between`子句实现。文中包含视频讲解,并通过创建测试表、插入数据及执行查询等步骤,演示如何获取历史版本信息和伪列详情,帮助用户深入了解该功能的实际应用。
193 13
|
前端开发 JavaScript
Webpack 常用 Loader 和 Plugin
【10月更文挑战第12天】Webpack 是一个强大的模块打包工具,能够将各种资源模块进行打包和处理。Loader 用于转换模块的源代码,如 `babel-loader` 将 ES6+ 代码转换为 ES5,`css-loader` 处理 CSS 文件等。Plugin 扩展 Webpack 功能,如 `HtmlWebpackPlugin` 自动生成 HTML 文件,`UglifyJsPlugin` 压缩 JavaScript 代码。通过合理配置和使用 Loader 和 Plugin,可以构建高效、优化的项目。
337 58
|
负载均衡 算法 Java
腾讯面试:说说6大Nginx负载均衡?手写一下权重轮询策略?
尼恩,一位资深架构师,分享了关于负载均衡及其策略的深入解析,特别是基于权重的负载均衡策略。文章不仅介绍了Nginx的五大负载均衡策略,如轮询、加权轮询、IP哈希、最少连接数等,还提供了手写加权轮询算法的Java实现示例。通过这些内容,尼恩帮助读者系统化理解负载均衡技术,提升面试竞争力,实现技术上的“肌肉展示”。此外,他还提供了丰富的技术资料和面试指导,助力求职者在大厂面试中脱颖而出。
腾讯面试:说说6大Nginx负载均衡?手写一下权重轮询策略?
Ceres库中参数理解
Ceres库中参数的理解,特别是仿函数中传参的含义,并提供了一个LeetCode问题的链接,该问题要求找出数组中和为目标值的两个数。
165 0
|
SQL 存储 自然语言处理
ES 在舆情搜索中的实践- Elastic Stack 实战手册
网络舆情监测,主要是利用互联网信息采集技术,以及自然语言处理等智能信息处理技术,通过对互联网公开数据进行自动化抓取,然后对信息进行结构化、自动分类、文本聚类、主题发现与跟踪等,提供信息检索、多维度统计、敏感信息预警、信息简报、自动化报告等功能,帮助用户及时发现危害品牌形象的观点,并为用户分析关注对象在网络中的形象提供依据。
1451 0
ES 在舆情搜索中的实践- Elastic Stack 实战手册
|
Java
Java面向对象编程,如何定义一个接口并在类中实现它?
Java面向对象编程,如何定义一个接口并在类中实现它?
314 1
|
安全 网络协议 Windows