当前位置: 首页 > article >正文

CAS

文章目录

  • CAS
    • 原子整数
    • 原子引用
    • Unsafe

CAS

CAS(Compare and Swap,比较并交换)基本思想是,在更新某个值之前,先比较其内存中的值是否与预期的值相等,如果相等,则进行更新;如果不相等,则不更新。

结合 CAS 和 volatile 可以实现无锁并发,适用于线程数少、多核 CPU 的场景下。

  • CAS 是基于乐观锁的思想:最乐观的估计,不怕别的线程来修改共享变量,就算改了也没关系,我吃亏点再 重试呗。
  • synchronized 是基于悲观锁的思想:最悲观的估计,得防着其它线程来修改共享变量,我上了锁你们都别想 改,我改完了解开锁,你们才有机会。
  • CAS 体现的是无锁并发、无阻塞并发,请仔细体会这两句话的意思 因为没有使用 synchronized,所以线程不会陷入阻塞,这是效率提升的因素之一 但如果竞争激烈,可以想到重试必然频繁发生,反而效率会受影响

原子整数

AtomicInteger i = new AtomicInteger(0);

 // 获取并自增(i = 0, 结果 i = 1, 返回 0),类似于 i++
 System.out.println(i.getAndIncrement());

 // 自增并获取(i = 1, 结果 i = 2, 返回 2),类似于 ++i
 System.out.println(i.incrementAndGet());

 // 自减并获取(i = 2, 结果 i = 1, 返回 1),类似于 --i
 System.out.println(i.decrementAndGet());

 // 获取并自减(i = 1, 结果 i = 0, 返回 1),类似于 i-
System.out.println(i.getAndDecrement());

 // 获取并加值(i = 0, 结果 i = 5, 返回 0)
System.out.println(i.getAndAdd(5));

 // 加值并获取(i = 5, 结果 i = 0, 返回 0)
System.out.println(i.addAndGet(-5));

 // 获取并更新(i = 0, p 为 i 的当前值, 结果 i = -2, 返回 0)
// 其中函数中的操作能保证原子,但函数需要无副作用
System.out.println(i.getAndUpdate(p -> p - 2));

 // 更新并获取(i = -2, p 为 i 的当前值, 结果 i = 0, 返回 0)
// 其中函数中的操作能保证原子,但函数需要无副作用
System.out.println(i.updateAndGet(p -> p + 2));

 // 获取并计算(i = 0, p 为 i 的当前值, x 为参数1, 结果 i = 10, 返回 0)
// 其中函数中的操作能保证原子,但函数需要无副作用
// getAndUpdate 如果在 lambda 中引用了外部的局部变量,要保证该局部变量是 final 的
// getAndAccumulate 可以通过 参数1 来引用外部的局部变量,但因为其不在 lambda 中因此不必是 final
 System.out.println(i.getAndAccumulate(10, (p, x) -> p + x));

 // 计算并获取(i = 10, p 为 i 的当前值, x 为参数1, 结果 i = 0, 返回 0)
// 其中函数中的操作能保证原子,但函数需要无副作用
System.out.println(i.accumulateAndGet(-10, (p, x) -> p + x))

原子引用

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

public class Test07 {
    public static void main(String[] args) throws InterruptedException {
        AtomicReference<BigDecimal> bigDecimal = new AtomicReference<>(new BigDecimal(10000));
        List<Thread> threads = new ArrayList<>();
        long start = System.nanoTime();
        for(int i=0;i<10000;i++){
            Thread thread = new Thread(() -> {
                while (true){
                    BigDecimal pre = bigDecimal.get();
                    if (bigDecimal.compareAndSet(pre,pre.subtract(new BigDecimal(1)))) {
                        break;
                    }
                }
            });
            threads.add(thread);
        }
        for(Thread t:threads){
            t.start();
        }
        for (Thread t:threads){
            t.join();
        }
        long end = System.nanoTime();
        System.out.println(bigDecimal.get() + " cost: " + (end - start) / 1000_000 + " ms");
    }
}

Unsafe

public class GetUnsafe {
	public static void main(String[] args) throws Exception {
		// 通过反射获得Unsafe对象
		Class unsafeClass = Unsafe.class;
		// 获得构造函数,Unsafe的构造函数为私有的
		Constructor constructor = unsafeClass.getDeclaredConstructor();
		// 设置为允许访问私有内容
		constructor.setAccessible(true);
		// 创建Unsafe对象
		Unsafe unsafe = (Unsafe) constructor.newInstance();
		
		// 创建Person对象
		Person person = new Person();
		// 获得其属性 name 的偏移量
		Field field = Person.class.getDeclaredField("name");
		long offset = unsafe.objectFieldOffset(field);

		// 通过unsafe的CAS操作改变值
		unsafe.compareAndSwapObject(person, offset, null, "Nyima");
		System.out.println(person);
	}
}

class Person {
    // 配合CAS操作,必须用volatile修饰
 	volatile String name;


	@Override
	public String toString() {
		return "Person{" +
				"name='" + name + '\'' +
				'}';
	}
}

http://www.kler.cn/a/291776.html

相关文章:

  • Linux 中检查 Apache Web Server (httpd) 正常运行时间的 4 种方法
  • 未来趋势系列 篇五:自主可控科技题材解析和股票梳理
  • OpenGL ES 01 渲染一个四边形
  • FPGA:FPGA器件选型
  • Linux shell脚本用于常见图片png、jpg、jpeg、tiff格式批量转webp格式后,并添加文本水印
  • css常用属性有哪些
  • 面试总结1
  • 前端模拟面试:如何检查JavaScript对象属性是否存在?
  • 分类预测|基于雪消融优化极端梯度提升的数据分类预测Matlab程序SAO-XGBoost 多特征输入多类别输出
  • 安防监控视频打手机检测算法核心技术打手机检测算法源码、模型简介
  • 阿里云对象存储服务(Aliyun OSS):企业级云存储解决方案
  • 毒枸杞事件启示录:EasyCVR视频AI智能监管方案如何重塑食品卫生安全防线
  • matter消息中的组播和广播
  • 鼠标控制dom元素的大小。采用ResizeObserver——监听元素大小的变化
  • uni-app全局引入js文件
  • .Net 6.0--通用帮助类--FileHelper
  • 打卡57天------图论(两种算法)
  • Leetcode刷题笔记:多数元素(摩尔投票算法最通俗的理解)
  • 设计模式学习-责任链模式
  • 结构型设计模式--装饰模式
  • 【Spring Boot-Spring Boot配置文件分类】
  • 前端面试题总结(HTML篇和CSS篇)
  • Spring Boot应用中集成与使用多数据源
  • 【ES常用查询操作】
  • Java项目: 基于SpringBoot+mysql高校心理教育辅导管理系统分前后台(含源码+数据库+开题报告+毕业论文)
  • sql日期函数