6.4 原子引用

news2024/11/25 16:34:23

1、什么是原子引用

原子引用以cas的方式实现控制多线程之前的同步,从而保证多线程的安全性

原子引用主要有以下三个类

  • AtomicReference
  • AtomicStampReference
  • AtomicMarkableReference

2、demo演示

@Slf4j(topic = "c.Test35")
public class Test35 {
    public static void main(String[] args) {
        DecimalAccount.demo(new DecimalAccountCas(new BigDecimal("10000")));
    }
}

class DecimalAccountCas implements DecimalAccount {
    private AtomicReference<BigDecimal> balance;

    public DecimalAccountCas(BigDecimal balance) {
//        this.balance = balance;
        this.balance = new AtomicReference<>(balance);
    }

    @Override
    public BigDecimal getBalance() {
        return balance.get();
    }

    @Override
    public void withdraw(BigDecimal amount) {
        while(true) {
            BigDecimal prev = balance.get();
            BigDecimal next = prev.subtract(amount);
            if (balance.compareAndSet(prev, next)) {
                break;
            }
        }
    }
}

interface DecimalAccount {
    // 获取余额
    BigDecimal getBalance();

    // 取款
    void withdraw(BigDecimal amount);

    /**
     * 方法内会启动 1000 个线程,每个线程做 -10 元 的操作
     * 如果初始余额为 10000 那么正确的结果应当是 0
     */
    static void demo(DecimalAccount account) {
        List<Thread> ts = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            ts.add(new Thread(() -> {
                account.withdraw(BigDecimal.TEN);
            }));
        }
        ts.forEach(Thread::start);
        ts.forEach(t -> {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        System.out.println(account.getBalance());
    }
}

3、ABA的问题以及解决

AtomicStampedReference

主线程仅能判断出共享变量的值与最初值 A 是否相同,不能感知到这种从 A 改为 B 又 改回 A 的情况,如果主线程希望:
只要有其它线程【动过了】共享变量,那么自己的 cas 就算失败,这时,仅比较值是不够的,需要再加一个版本号

AtomicStampedReference : 可以给原子引用加上版本号,追踪原子引用整个的变化过程,如: A -> B -> A ->
C ,通过AtomicStampedReference,我们可以知道,引用变量中途被更改了几次

@Slf4j(topic = "c.Test36")
public class Test36 {

    static AtomicStampedReference<String> ref = new AtomicStampedReference<>("A", 0);

    public static void main(String[] args) throws InterruptedException {
        log.debug("main start...");
        // 获取值 A
        String prev = ref.getReference();
        // 获取版本号
        int stamp = ref.getStamp();
        log.debug("版本 {}", ref.getStamp());
        // 如果中间有其它线程干扰,发生了 ABA 现象
        other();
        sleep(1);
        // 尝试改为 C
        log.debug("版本 {}", ref.getStamp());
        log.debug("change A->C {}", ref.compareAndSet(prev, "C", stamp, stamp + 1));
    }

    private static void other() {
        new Thread(() -> {
            log.debug("版本 {}", ref.getStamp());
            log.debug("change A->B {}", ref.compareAndSet(ref.getReference(), "B", ref.getStamp(), ref.getStamp() + 1));
            log.debug("更新版本为 {}", ref.getStamp());
        }, "t1").start();
        sleep(0.5);
        new Thread(() -> {
            log.debug("版本 {}", ref.getStamp());
            log.debug("change B->A {}", ref.compareAndSet(ref.getReference(), "A", ref.getStamp(), ref.getStamp() + 1));
            log.debug("更新版本为 {}", ref.getStamp());
        }, "t2").start();
    }
}

在这里插入图片描述

AtomicMarkableReference

是有时候,并不关心引用变量更改了几次,只是单纯的关心是否更改过,所以就有了AtomicMarkableReference

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/701534.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++day2

一、类和结构体的区别 成员访问权限&#xff1a;类中的成员默认是私有的&#xff0c;需要使用访问修饰符&#xff08;如public、private、protected&#xff09;来显式指定访问权限。而结构体中的成员默认是公共的&#xff0c;即可以直接访问。 继承&#xff1a;类支持继承&am…

面向对象高级实战演练之银行系统

面向对象高级实战演练之银行系统 实现功能&#xff1a; 1. 银行管理员(使用管理员密码)查看所有用户信息 2. 进入银行系统提示功能 3. 用户密码管理 4. 账户开户/销户 5. 存款/取款 6. 用户间转账 7. 用户余额查询 8. 常见错误检查和提示代码实现&#xff1a; import random…

【LeetCode】动态规划 刷题训练(六)

文章目录 123. 买卖股票的最佳时机 III题目解析零笔交易一笔交易两笔交易 状态转移方程f[i][j]状态转移方程g[i][j]状态转移方程 初始化完整代码 188. 买卖股票的最佳时机 IV题目解析状态转移方程f[i][j]状态转移方程g[i][j]状态转移方程 初始化完整代码 53. 最大子数组和状态转…

vhost-net-原理-初始化流程-数据传输流程

文章目录 1.vhost net2.vhost-net的初始化流程vhost net设置vhost dev设置vhost vring设置 3.数据收发流程分析3.1 数据发送3.2 数据接收 4ioventfd和irqfd的通知机制4.1ioeventfdqemu侧kvm侧总体效果 4.2irqfdqemu侧kvm侧总体效果 参考&#xff1a; 1.vhost net 传统的virtio…

深入理解Java虚拟机jvm-垃圾收集器日志参数

垃圾收集器日志参数 查看GC基本信息查看GC详细信息查看GC前后的堆、方法区可用容量变化查看GC过程中用户线程并发时间以及停顿的时间查看收集器Ergonomics机制&#xff08;自动设置堆空间各分代区域大小、收集目标等内容&#xff0c;从Parallel收集器开始支持&#xff09;自动调…

windows下nginx location root路径问题

Windows版本nginx的多级路径问题 windows 下 nginx location root路径为多级目录的问题解决方案&#xff1a;使用双反斜杠--\\Windows版本的nginx常用命令一览&#xff1a; windows 下 nginx location root路径为多级目录的问题 nginx的windows版本中location路径为多级目录 需…

Git客户端:Tower for Mac 注册版

Tower是一款Mac OS X系统上的Git客户端软件&#xff0c;它提供了丰富的功能和工具&#xff0c;帮助用户更加方便地管理和使用Git版本控制系统。以下是Tower的一些特点&#xff1a; 1. 界面友好&#xff1a;Tower的界面友好&#xff0c;使用户能够轻松地掌握软件的使用方法。 …

【vs2022】MSVCRTD.lib 4098: 默认库“libcmtd.lib”与其他库的使用冲突

verbose-print- 整理&#xff1a;warning LNK4098: 默认库“LIBCMT”与其他库的使用冲突&#xff1b;请使用 /NODEFAULTLIB:library 讲解的非常详细&#xff1a; Linker 加入命令行选项 To set this linker option in the Visual Studio development environment Open the p…

Chapter 1: Introduction - Why Program? | Python for Everybody 讲义_En

文章目录 Python for Everybody课程简介Python for Everybody (Why Program?)Why should you learn to write programs?Creativity and motivationComputer hardware architectureUnderstanding programmingWords and sentencesConversing with PythonTerminology: Interpret…

MyBatis全篇

文章目录 MyBatis特性下载持久化层技术对比 搭建MyBatis创建maven工程创建MyBatis的核心配置文件创建mapper接口创建MyBatis的映射文件测试功能加入log4j日志功能加入log4j的配置文件 核心配置文件的完善与详解MyBatis的增删改查测试功能 MyBatis获取参数值在IDEA中设置中配置文…

Java Web HTMLCSS(2)23.6.28

2&#xff0c;CSS 2.1 概述 CSS 是一门语言&#xff0c;用于控制网页表现。我们之前介绍过W3C标准。W3C标准规定了网页是由以下组成&#xff1a; 结构&#xff1a;HTML表现&#xff1a;CSS行为&#xff1a;JavaScript CSS也有一个专业的名字&#xff1a;Cascading Style Sh…

Springboot 如何自动上传秒杀商品数据到Redis中上架商品

一、概述 如下图秒杀活动&#xff1a; 在这个秒杀活动中&#xff0c;需要自动上架一定时间段的商品&#xff0c;我们如何实现自动上传呢&#xff1f; 我们可以通过定时任务来实现的。在秒杀活动开始前&#xff0c;需要将商品信息存储到数据库中&#xff0c;并设置好库存和价格…

Linux学习之进程的通信方式信号:kill命令

kill -l可以看到可以使用信号量。 把下边的内容使用编辑器&#xff0c;比如vim写到./a.sh。 #!/bin/bashecho $$ while : # 无限循环 do: donecat a.sh看一下文件里边的内容。 chmod ur,ux a.sh给当前用户赋予a.sh文件的写和执行权限。 在第一个端口里边&#xff0c;使用./a…

在 TypeScript 中有效地使用 keyof 和 typeof 来表示类型

在本文中&#xff0c;我们将学习如何通过组合类型运算符和枚举来提取和声明常量类型typeof&#xff0c;以使您的代码库得到优化。keyof 先决条件 为了获得更好的编码体验&#xff0c;您应该在 IDE 中安装 TypeScript&#xff0c;例如VSCode。它将为您提供许多基本功能&#xff…

Linux——进程通信之共享内存

目录 一. 回顾上文 二.共享内存 1.定义 2.特点&#xff1a; 3.实现步骤&#xff1a; 如下为成功链接共享内存使用权的完整步骤&#xff1a; 4.函数介绍 4.1shmget函数 4.1.2参数介绍 4.2ftok函数&#xff1a; 4.2.1参数介绍 关于ftok(); shmget();函数的代码实验…

基于当量因子法、InVEST、SolVES模型等多技术融合在生态系统服务功能社会价值评估中的应用

查看原文>>>基于当量因子法、InVEST、SolVES模型等多技术融合在生态系统服务功能社会价值评估中的应用及论文写作、拓展分析 本文将讲述用于评估生态系统服务价值的当量因子法、InVEST模型、SolVES模型及其原理&#xff0c;您将学会三种模型的原理与运行方法&#xf…

基于Docker的JMeter分布式压测

目录 前言&#xff1a; Docker Docker在JMeter分布式测试中的作用 Dockerfile用于JMeter基础&#xff1a; Dockerfile for JMeter Server / Slave: 总结 前言&#xff1a; 基于Docker的JMeter分布式压测是一种将JMeter测试分布在多个容器中进行的方法&#xff0c;可以提高…

《计算机系统2》学习笔记

目录 计算机系统漫游 Amdahl定理 信息的表示和处理 信息存储 进制转化 小端法 大端法 布尔代数 位级运算 逻辑运算 移位运算 整数表示 无符号数编码 补码编码 有符号数和无符号数之间的转换 扩展数的位表示 截断数字 整数运算 无符号加法 无符号数求反 有…

信号链噪声分析5

目录 概要 整体架构流程 技术名词解释 技术细节 小结 概要 提示&#xff1a;这里可以添加技术概要 残余相位噪声测量法消除了外部噪声源&#xff08;例如电源或输入时钟&#xff09;的影响&#xff0c;而绝对相位 噪声测量法包含了这些来源的噪声。残余相位噪声装置可以隔离并…

Upload靶场通关笔记

文章目录 一、Pass-011.抓包上传2.获取上传路径3.工具验证 二、Pass-02三、Pass-031.使用httpd.conf自定义后缀2.提取上传文件名3.工具测试4.注意点四、Pass-041.上传.htaccess2.上传图片3.工具测试 五、Pass-05六、Pass-061.空格.号绕过2.工具测试 七、Pass-07八、Pass-081.特…