CAS

1:CAS是什么?

比较并交换 (compareAndSwap),是一条CPU并发原语,是乐观锁技术的一种实现,当多个线程尝试使用CAS同时修改同一个变量时,只有其中一个线程能修改变量的值,而其它线程都失败,失败的线程并不会被挂起或者结束,

而是继续尝试(循环比较)修改,直到修改成功

源码一览:

    public final int getAndAddInt(Object var1, long var2, int var4) {        int var5;        do {
//获取数据 var5
= this.getIntVolatile(var1, var2);
      //比较数据 v1和v2找到值 和v5做比较 }
while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4)); return var5; }

v1是当前对象,v2是内存地址偏移量,通过v1和v2可以查找到一个精确的数据并拷贝到自己线程工作区域内,然后根据这个数据和v5进行比较,只要是一致的,那么执行v5 + v4

当线程被切换过之后,那么此时,v5还是v5,但是v1和v2的值却不一定等于v5了,因为已经切换过其他线程,其他线程可能对这个v1和v2已经做了修改,如果做了修改,那么将继续循环比较,如此往复,直到成功

优点:

  1:不加锁,通过unSafe类解决数据一致性问题

  2:直接操作主内存 不存在数据不一致问题

  3:通过自旋锁方式,对数据进行比较和交换

缺点:

  1:自旋锁对cpu开销特别大

  2:只能保证一个共享变量的原子操作

  3:导致ABA问题

ABA问题:

  两个线程通过cas操作同一个变量,当T1线程和T2线程都获得主内存X的时候,T1的期望值是A想要修改成B,但是T2线程快速的将主内存A修改为任意值,然后又将任意值修改回A,此时T1再次获取主内存 值的时候发现 还是A就做了修改。表面上程序是正常运行的,但是这个过程中这个值是存在多变的,不保证这个过程没有问题!

代码示例:
import java.util.concurrent.TimeUnit;import java.util.concurrent.atomic.AtomicReference;public class test {    static AtomicReference<Integer> atomicReference = new AtomicReference<>(100);    public static void main(String[] args) {        new Thread(() -> {            atomicReference.compareAndSet(100,101);            atomicReference.compareAndSet(101,100);        },"t1").start();        new Thread(() -> {            try {                TimeUnit.SECONDS.sleep(2);                                //在本次修改之前 其实数据已经被修改过,但是此处只做第一次和最后一次的比较,发现100=100,所以就直接继续修改完成                System.out.println(atomicReference.compareAndSet(100, 2000) + " 	 getVaue:" + atomicReference.get());            }catch (Exception d){                d.printStackTrace();            }        },"t2").start();    }}

 

解决ABA问题:

  通过 AtomicStampedReference来添加版号作为修改的依据,如下代码,只要ABA发生,数据则修改失败!

import java.util.concurrent.TimeUnit;import java.util.concurrent.atomic.AtomicReference;import java.util.concurrent.atomic.AtomicStampedReference;public class test {    static AtomicReference<Integer> atomicReference = new AtomicReference<>(100);    static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100,1);    public static void main(String[] args) {        new Thread(() -> {            atomicReference.compareAndSet(100,101);            atomicReference.compareAndSet(101,100);        },"t1").start();        new Thread(() -> {            try {                TimeUnit.SECONDS.sleep(2);                System.out.println(atomicReference.compareAndSet(100, 2000) + " 	 getVaue:" + atomicReference.get());            }catch (Exception d){                d.printStackTrace();            }  新疆干部培训 http://xj.ganxun.cn/        },"t2").start();        //处理ABA问题        new Thread(() -> {            try {                TimeUnit.SECONDS.sleep(3);            }catch (Exception e){                e.printStackTrace();            }            atomicStampedReference.compareAndSet(100,200,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);            atomicStampedReference.compareAndSet(200,100,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);        },"t3").start();        new Thread(() -> {            int stamp = atomicStampedReference.getStamp();            try {                TimeUnit.SECONDS.sleep(3);            }catch (Exception e){                e.printStackTrace();            }            boolean b = atomicStampedReference.compareAndSet(100, 500, stamp, stamp + 1);            System.out.println(Thread.currentThread().getName() + " 	 版本号:" + stamp + ",当前版本号: "+atomicStampedReference.getStamp()+"修改结果:" + b                    + ",实际值是:" + atomicStampedReference.getReference());        },"t4").start();    }}

 

内容概要:本文介绍了一个基于Matlab的综合能源系统优化调度仿真资源,重点实现了含光热电站、有机朗肯循环(ORC)和电含光热电站、有机有机朗肯循环、P2G的综合能源优化调度(Matlab代码实现)转气(P2G)技术的冷、热、电多能互补系统的优化调度模型。该模型充分考虑多种能源形式的协同转换与利用,通过Matlab代码构建系统架构、设定约束条件并求解优化目标,旨在提升综合能源系统的运行效率与经济性,同时兼顾灵活性供需不确定性下的储能优化配置问题。文中还提到了相关仿真技术支持,如YALMIP工具包的应用,适用于复杂能源系统的建模与求解。; 适合人群:具备一定Matlab编程基础和能源系统背景知识的科研人员、研究生及工程技术人员,尤其适合从事综合能源系统、可再生能源利用、电力系统优化等方向的研究者。; 使用场景及目标:①研究含光热、ORC和P2G的多能系统协调调度机制;②开展考虑不确定性的储能优化配置与经济调度仿真;③学习Matlab在能源系统优化中的建模与求解方法,复现高水平论文(如EI期刊)中的算法案例。; 阅读建议:建议读者结合文档提供的网盘资源,下载完整代码和案例文件,按照目录顺序逐步学习,重点关注模型构建逻辑、约束设置与求解器调用方式,并通过修改参数进行仿真实验,加深对综合能源系统优化调度的理解。
08-06
### CAS与Java内存管理的关系 CAS(Compare-And-Swap)是一种无锁的原子操作机制,广泛应用于Java的并发编程中,尤其是在Java的`java.util.concurrent.atomic`包中的`AtomicInteger`、`AtomicReference`等类中。CAS操作通过直接调用底层CPU指令实现,确保在多线程环境下对共享变量的操作是原子性的,从而避免使用锁带来的性能开销和死锁问题。 CAS在Java中是通过`sun.misc.Unsafe`类提供的本地方法实现的,这些方法调用了JNI(Java Native Interface)来与底层硬件交互。具体来说,CAS操作依赖于处理器提供的原子指令,如`cmpxchg`(在x86架构上)等,这些指令在执行时不会被中断,从而保证了操作的原子性[^3]。 以下是CAS操作的三个核心方法,它们用于对不同类型的数据进行比较并交换: ```java public final native boolean compareAndSwapObject(Object o, long offset, Object expected, Object x); public final native boolean compareAndSwapInt(Object o, long offset, int expected, int x); public final native boolean compareAndSwapLong(Object o, long offset, long expected, long x); ``` 这些方法接受四个参数:对象实例、字段的内存偏移量、期望值和新值。只有当当前值等于期望值时,才会将新值写入内存,否则不做任何操作。这种方式在Java并发编程中被广泛用于实现非阻塞算法[^2]。 ### CAS在Java内存管理中的作用 在Java内存管理中,CAS主要用于实现线程安全的共享变量操作,尤其是在`Atomic`系列类中。例如,`AtomicInteger`类中的`incrementAndGet()`方法内部就是使用CAS来实现自增操作的。这种方式避免了传统锁机制带来的上下文切换和阻塞开销。 以下是一个使用`AtomicInteger`的示例: ```java import java.util.concurrent.atomic.AtomicInteger; public class CasExample { private static AtomicInteger count = new AtomicInteger(0); public static void increment() { count.incrementAndGet(); // 使用CAS实现的原子自增 } public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(() -> { for (int i = 0; i < 1000; i++) { increment(); } }); Thread t2 = new Thread(() -> { for (int i = 0; i < 1000; i++) { increment(); } }); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println("Final count is : " + count.get()); } } ``` 在上述代码中,`incrementAndGet()`方法内部使用了CAS操作,确保在多线程环境下对`count`变量的自增操作是线程安全的。 ### CAS的ABA问题及其解决方案 尽管CAS操作是原子的,但它仍然存在一个经典的**ABA问题**。即:如果一个变量的值从A变为B,再变回A,此时CAS操作会认为该变量没有发生变化,从而允许更新。然而,这种情况下变量实际上已经发生了变化,只是最终值与原始值相同。 ABA问题的典型场景是一个使用CAS实现的无锁链表栈结构。假设栈顶为A,线程T1读取A的下一个节点为B,准备将栈顶替换为B。在T1执行CAS之前,线程T2将A和B弹出,压入了C和D,最后又将A压入栈顶。此时栈顶仍然是A,但B的下一个节点已经是null。T1执行CAS时发现栈顶仍然是A,于是将栈顶设置为B,但此时B的next为null,导致C和D被丢失[^5]。 解决ABA问题的常见方法是引入**版本号(Versioning)**或**时间戳(Timestamp)**。每次修改变量时,不仅修改其值,还同时更新版本号。这样即使值变回A,版本号也会不同,从而避免ABA问题。Java中提供了`AtomicStampedReference`类来实现带有版本号的原子引用操作。 示例如下: ```java import java.util.concurrent.atomic.AtomicStampedReference; public class ABAExample { private static AtomicStampedReference<Integer> atomicRef = new AtomicStampedReference<>(1, 0); public static void main(String[] args) { Thread t1 = new Thread(() -> { boolean success = atomicRef.compareAndSet(1, 2, 0, 1); System.out.println("Thread 1 CAS result: " + success); }); Thread t2 = new Thread(() -> { boolean success = atomicRef.compareAndSet(1, 2, 0, 1); System.out.println("Thread 2 CAS result: " + success); success = atomicRef.compareAndSet(2, 1, 1, 2); // 修改回1,并更新版本号 System.out.println("Thread 2 revert result: " + success); }); t2.start(); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } t1.start(); } } ``` ### 相关问题 CAS机制虽然高效,但在Java内存管理中也存在一些挑战和限制,例如: - **ABA问题**:如前所述,可以通过引入版本号来解决。 - **自旋开销**:CAS失败后通常会重试,这可能导致线程长时间自旋,浪费CPU资源。 - **只能保证单个变量的原子性**:对于多个变量的操作,CAS无法保证整体的原子性,需要结合其他机制(如锁或事务内存)来实现。 ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值