JUC并发编程——CAS与原子引用(基于狂神说的学习笔记)

CAS

CAS与原子引用涉及到JVM以及更底层的一些知识,笔者会在JVM篇中写的更细致一点

什么是CAS

CAS 是Java设置的CPU的并发原语

Java是无法直接操作内存的

但Java可以调用C++

而C++可以操作内存

Java可以通过native类调用C++来操作内存

CAS = Compare And Set 比较并交换

CAS是:比较当前内存中的值和主内存中的值,如果这个值是期望的,那么则执行操作,如果不是就一直循环比较(自循环)

缺点:

1、自循环会耗时

2、一次性职能保证一个共享变量的原子性

3、会存在ABA问题

/**
 * Atomically sets the value to newValue
 * if the current value code == expectedValue,
 * with memory effects as specified by VarHandle#compareAndSet.
 *
 * @param expectedValue the expected value
 * @param newValue the new value
 * @return true if successful. False return indicates that
 * the actual value was not equal to the expected value.
 */
public final boolean compareAndSet(int expectedValue, int newValue) {
    return U.compareAndSetInt(this, VALUE, expectedValue, newValue);
}
package CAS;

import java.util.concurrent.atomic.AtomicInteger;

public class casDemo {

    // CAS 是CPU的并发原语
    // compareAndSet:比较并交换
    public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(2020);
        // public final boolean compareAndSet(int expectedValue, int newValue)
        // expectedValue:期望值    newValue:更新值
        // 比较,如果期望值达到了,则变为更新值,否则就不跟新
        atomicInteger.compareAndSet(2020,2023);
        System.out.println(atomicInteger.get());

        System.out.println(atomicInteger.compareAndSet(2020, 2023));
    }
}

原子引用

带版本号的原子操作 解决ABA问题! 与乐观锁很相似!

package CAS;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicStampedReference;

public class casDemo02 {
// AtomicStampedReference 注意,如果泛型时一个包装类,注意对象的引用问题
    public static void main(String[] args) {
        AtomicStampedReference<Integer> atomicInteger = new AtomicStampedReference<>(1,1);

        new Thread(()->{
            // 获得目前的版本号(时间戳)
            int stamp = atomicInteger.getStamp();
            System.out.println("A1=>"+stamp);

            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            System.out.println(atomicInteger.compareAndSet(1, 2, atomicInteger.getStamp(), atomicInteger.getStamp() + 1));
            System.out.println("A2=>"+atomicInteger.getStamp());
            System.out.println(atomicInteger.compareAndSet(2, 1, atomicInteger.getStamp(), atomicInteger.getStamp() + 1));
            System.out.println("A3=>"+atomicInteger.getStamp());

        },"A").start();

        new Thread(()->{
            // 获得目前的版本号(时间戳)
            int stamp = atomicInteger.getStamp();
            System.out.println("B1=>"+stamp);

            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            System.out.println(atomicInteger.compareAndSet(1, 6, stamp, stamp + 1));
            System.out.println("B1=>"+atomicInteger.getStamp());
        },"B").start();


    }
}

注意:

Integer使用了对象缓存机制,默认范围是-128~127,推荐使用静态工厂方法valueOf获取对象实例,而不是new,因为valuOf使用缓存,而new一定会创建新的对象分配新的内存空间;

在示例中,我们一开始使用的expectedRefrence 和 newReference 都是大于127的且使用new获取对象,因此,内存中创造了新的对象分配新的空间,所以使用cas时一直为false

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苏三有春

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值