【实战Java高并发程序设计 2】无锁的对象引用:AtomicReference

Java8新特性 /利用Java8新特性实现一个包含若干字符串list集合,利用流式编程对集合中以张开头,字符串长度为3的数据进行过滤。//distinct:元素去重,依赖(hashCode和equals) concat:合并a和b为一个流。//注意: of后面如果跟数据,必须是引用数据类型,如果是基本数据类型只会打印该数组的地址值。//toMap:参数一:键生成规则,参数二:值生成规则,注意点:键不能重复。//修改Stream流中的数据,不会影响原来集合或数组中的数据。对map集合中对象的字段设置值。 阅读详情
摘要: AtomicReference和AtomicInteger非常类似,不同之处就在于AtomicInteger是对整数的封装,而AtomicReference则对应普通的对象引用。也就是它可以保证你在修改对象引用时的线程安全性。在介绍AtomicReference的同时,我希望同时提出一个有关原子操作的逻辑上的不足。

  AtomicReference和AtomicInteger非常类似,不同之处就在于AtomicInteger是对整数的封装,而AtomicReference则对应普通的对象引用。也就是它可以保证你在修改对象引用时的线程安全性。在介绍AtomicReference的同时,我希望同时提出一个有关原子操作的逻辑上的不足。

   之前我们说过,线程判断被修改对象是否可以正确写入的条件是对象的当前值和期望是否一致。这个逻辑从一般意义上来说是正确的。但有可能出现一个小小的例外,就是当你获得对象当前数据后,在准备修改为新值前,对象的值被其他线程连续修改了2次,而经过这2次修改后,对象的值又恢复为旧值。这样,当前线程就无法正确判断这个对象究竟是否被修改过。如图4.2所示,显示了这种情况。

图4.2 对象值被反复修改回原数据

   一般来说,发生这种情况的概率很小。而且即使发生了,可能也不是什么大问题。比如,我们只是简单得要做一个数值加法,即使在我取得期望值后,这个数字被不断的修改,只要它最终改回了我的期望值,我的加法计算就不会出错。也就是说,当你修改的对象没有过程的状态信息,所有的信息都只保存于对象的数值本身。

    但是,在现实中,还可能存在另外一种场景。就是我们是否能修改对象的值,不仅取决于当前值,还和对象的过程变化有关,这时,AtomicReference就无能为力了。

打一个比方,如果有一家蛋糕店,为了挽留客户,绝对为贵宾卡里余额小于20元的客户一次性赠送20元,刺激消费者充值和消费。但条件是,每一位客户只能被赠送一次。

现在,我们就来模拟这个场景,为了演示AtomicReference,我在这里使用AtomicReference实现这个功能。首先,我们模拟用户账户余额。

定义用户账户余额:

static AtomicReference<Integer> money=newAtomicReference<Integer>();
// 设置账户初始值小于20,显然这是一个需要被充值的账户
money.set(19);


接着,我们需要若干个后台线程,它们不断扫描数据,并为满足条件的客户充值。

01 //模拟多个线程同时更新后台数据库,为用户充值
02 for(int i = 0 ; i < 3 ; i++) {             
03     new Thread(){ 
04         publicvoid run() { 
05            while(true){
06                while(true){
07                    Integer m=money.get();
08                    if(m<20){
09                        if(money.compareAndSet(m, m+20)){
10                  System.out.println("余额小于20元,充值成功,余额:"+money.get()+"元");
11                             break;
12                        }
13                    }else{
14                        //System.out.println("余额大于20元,无需充值");
15                         break ;
16                    }
17                 }
18             }
19         } 
20     }.start();
21 }


上述代码第8行,判断用户余额并给予赠予金额。如果已经被其他用户处理,那么当前线程就会失败。因此,可以确保用户只会被充值一次。

此时,如果很不幸的,用户正好正在进行消费,就在赠予金额到账的同时,他进行了一次消费,使得总金额又小于20元,并且正好累计消费了20元。使得消费、赠予后的金额等于消费前、赠予前的金额。这时,后台的赠予进程就会误以为这个账户还没有赠予,所以,存在被多次赠予的可能。下面,模拟了这个消费线程:

01 //用户消费线程,模拟消费行为
02 new Thread() { 
03     public voidrun() { 
04         for(inti=0;i<100;i++){
05            while(true){
06                Integer m=money.get();
07                 if(m>10){
08                    System.out.println("大于10元");
09                    if(money.compareAndSet(m, m-10)){
10                        System.out.println("成功消费10元,余额:"+money.get());
11                        break;
12                    }
13                }else{
14                    System.out.println("没有足够的金额");
15                    break;
16                 }
17             }
18             try{Thread.sleep(100);} catch (InterruptedException e) {}
19         }
20     } 
21 }.start();


上述代码中,消费者只要贵宾卡里的钱大于10元,就会立即进行一次10元的消费。执行上述程序,得到的输出如下:

余额小于20元,充值成功,余额:39元
大于10元
成功消费10元,余额:29
大于10元
成功消费10元,余额:19
余额小于20元,充值成功,余额:39元
大于10元
成功消费10元,余额:29
大于10元
成功消费10元,余额:39
余额小于20元,充值成功,余额:39元


   从这一段输出中,可以看到,这个账户被先后反复多次充值。其原因正是因为账户余额被反复修改,修改后的值等于原有的数值。使得CAS操作无法正确判断当前数据状态。

   虽然说这种情况出现的概率不大,但是依然是有可能的出现的。因此,当业务上确实可能出现这种情况时,我们也必须多加防范。体贴的JDK也已经为我们考虑到了这种情况,使用AtomicStampedReference就可以很好的解决这个问题。

S32K144 SDK实战:FTM输入捕获模块的配置与应用 本文详细介绍了S32K144 SDK中FTM输入捕获模块的配置与应用实践。从基础认知到开发环境搭建,再到引脚配置和中断处理技巧,全面解析了如何利用FTM模块实现高精度信号测量。特别适用于电机控制、工业测速等场景,帮助开发者快速掌握S32K144的FTM输入捕获功能。 阅读详情

相关推荐

labview的TDMS文件读写

本文先介绍TDMS概念和文件结构,然后介绍VI如何使用,最后分析一个labview的自带范例

观则明的博客 1万+

AtomicReference

//一家商店为了挽留客户决定为贵宾卡里小于20元的用户免费充值20 //但是一个用户只能被充值一次 //运行以下程序你会发现用户一旦卡上余额小于20就会被充值20元 //这与只充值一次不相符 //其原因就是账户余额被反复修改,修改后等于原来的值 //使得CAS无法判断当前数据状态 //AtomicReference是对对象的引用,而AtomicInteger是对整数的引用 import jav...

qq_43776408的博客 509

如何在Tagetik系统中抽取处理SAP系统财务数据

如何在Tagetik系统中抽取处理不同核算系统财务数据:以SAP为例,简单讲一下Tagetik对接SAP数据的基本情况

2201_75401663的博客 578

String字符串判定是否为空方法总结

Java中判断String字符串不为空的方法一、判断一个字符串str不为空的方法有: 1. str!=null;(前提条件) 2. “”.equals(str); 3. str.length()!=0;( 注意:length是属性,一般集合类对象拥有的属性,取得集合的大小。 例如:数组.length就是取得数组的长度。 length()是

Vincent 1万+

飞腾X100芯片GPU状态查询

本文档对在linux系统下查看X100芯片GPU状态信息进行说明,可以帮助大家了解芯片的实时工作状态。

乌拉大喵喵 2820

QOpenGL入门教程(二)—— 第一个QOpenGLWidget程序

终于到了实际操作的环节了,这一章我们要做的是: 创建OpenGL窗口 创建并编写着色器程序 为着色器程序装配顶点数据 启动渲染管线进行绘图 第一步:创建新项目 首先,我们使用Qt创建一个常规的QWidget项目,建议不要勾选ui设计器(个人习惯,笔者不太习惯于使用ui来设计) 第二步:创建QOpenGLWidget并实现三个虚函数 QOpenGLWidget Qt5.4之前,Qt可以通过一个QGLWidget类来创建OpenGL窗口,但由于opengl的发展,在5.4版本的时候,Qt提供

ItaLink 1万+

Java基础

Java基础Java类初始化顺序String、StringBuffer、StringBuilder Java类初始化顺序 这是所有情况的类初始化顺序,如果实际类中没有定义则跳过:父类静态变量——父类静态代码块——子类静态代码块——父类非静态变量——父类非静态代码块——父类构造函数——子类非静态变量——子类非静态代码块——子类构造函数 String、StringBuffer、StringBuilder Stirng:final修饰,存放在字符串常量池或堆中 StringBuffer(内存中为字符串数组):线程

u013198899的博客 1099

强化学习经典算法笔记(九):LSTM加持的PolicyGradient算法

强化学习经典算法笔记(九):LSTM加持的PolicyGradient算法 在上文《强化学习经典算法笔记(八):LSTM加持的A2C算法解决POMDP问题》的基础上,实现了LSTM+MLP的Policy Gradient算法。 实现过程如下: import argparse, math, os, sys import numpy as np import gym from gym import wrappers import matplotlib.pyplot as plt import torch fr

hhy_csdn的博客 5636

无锁 java 实战高_【实战Java高并发程序设计2】无锁的对象引用:AtomicReference

AtomicReference和AtomicInteger非常类似,不同之处就在于AtomicInteger是对整数的封装,而AtomicReference则对应普通的对象引用。也就是它可以保证你在修改对象引用时的线程安全性。在介绍AtomicReference的同时,我希望同时提出一个有关原子操作的逻辑上的不足。之前我们说过,线程判断被修改对象是否可以正确写入的条件是对象的当前值和期望是否一致。...

weixin_29012765的博客 114

【C++】lambda表达式

本篇文章我们要学习的是lambda表达式,它是C++11新增的一种特别方便的语法,相较于之前的函数指针以及仿函数都方便了不少,下面就让我们一起来学习吧。

malloc不出对象的博客 2633

美特CRM mcc_login.jsp存在SQL注入漏洞

MetaCRM 是一种现代化的客户关系管理(CRM)平台,旨在通过集成和自动化的方式帮助企业管理与客户的关系,提高销售和服务效率。MetaCRM 的功能和特性通常涵盖了多个领域,包括销售、营销、客户服务、数据分析和自动化工具。

缘梦未来的博客 808

【实战Java高并发程序设计2】无锁的对象引用:AtomicReference

【实战Java高并发程序设计】连载1–Java中的指针:Unsafe类 AtomicReference和AtomicInteger非常类似,不同之处就在于AtomicInteger是对整数的封装,而AtomicReference则对应普通的对象引用。也就是它可以保证你在修改对象引用时的线程安全性。在介绍AtomicReference的同时...

weixin_33887443的博客 121

解锁机器人动态平衡算法:从原理到实践

机器人的动态平衡,是指机器人在运动过程中,面对各种复杂的动态变化和外界干扰,依然能够维持稳定状态,不发生倾倒或失去控制的能力。它就像是一位技艺精湛的舞者,在舞台上翩翩起舞时,无论做出多么复杂的动作,都能巧妙地调整身体姿态,始终保持平衡,展现出优美的舞姿。在实际应用中,机器人的动态平衡对于其稳定运行起着至关重要的作用。以双足机器人为例,当它行走在不平整的地面上时,地面的起伏会使机器人的重心不断发生变化。如果没有良好的动态平衡能力,机器人就很容易因为重心偏移而摔倒,无法完成行走任务。

远程部署调试 运行安装 项目调试 二次开发 项目技术新 持续迭代 部分源码免费分享 3839

无锁 java 实战高_【实战Java高并发程序设计 2】无锁的对象引用:AtomicReference...

AtomicReference和AtomicInteger非常类似,不同之处就在于AtomicInteger是对整数的封装,而AtomicReference则对应普通的对象引用。也就是它可以保证你在修改对象引用时的线程安全性。在介绍AtomicReference的同时,我希望同时提出一个有关原子操作的逻辑上的不足。之前我们说过,线程判断被修改对象是否可以正确写入的条件是对象的当前值和期望是否一致。...

weixin_29185493的博客 116

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

Spring Boot整合微信支付:物联网场景下的电子功德箱系统实战

移动支付作为现代商业交易的核心技术,其原理是通过安全的网络协议连接商户、用户与金融机构,实现资金的电子化流转。这项技术的价值在于极大地提升了交易效率与便捷性,并催生了丰富的线上线下融合应用场景。在物联网领域,支付系统与智能硬件的结合,正将传统线下服务数字化,例如智能零售、自助终端和智慧景区。本文聚焦于一个典型实践——电子功德箱系统,深入探讨如何利用Spring Boot后端框架与微信支付API,构建一个稳定、安全的物联网支付闭环。系统设计涵盖了从设备接入、订单生成、支付回调(异步通知)到状态同步的全流程,并

weixin_34236869的博客 309

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

【实战Java高并发程序设计】2–无锁的对象引用:AtomicReference

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_33882443的博客 91

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

java 对象引用赋值是否原子操作_【实战Java高并发程序设计 2】无锁的对象引用:AtomicReference...

AtomicReference和AtomicInteger非常类似,不同之处就在于AtomicInteger是对整数的封装,而AtomicReference则对应普通的对象引用。也就是它可以保证你在修改对象引用时的线程安全性。在介绍AtomicReference的同时,我希望同时提出一个有关原子操作的逻辑上的不足。之前我们说过,线程判断被修改对象是否可以正确写入的条件是对象的当前值和期望是否一致。...

weixin_32638607的博客 161

高并发编程之AtomicReference讲解

一、AtomicReference介绍 ①.AtomicReference和AtomicInteger非常类似,不同之处就在于AtomicInteger是对整数的封装,而AtomicReference则对应普通的对象引用。也就是它可以保证你在修改对象引用时的线程安全性。 ②.AtomicReference是作用是对”对象”进行原子操作。 提供了一种读和写都是原子性的对象引用变量。原子意味着多个线程...

weixin_42146366的博客 5万+

高并发编程之AtomicReference原子类讲解

高并发编程之Atomic原子类讲解

weixin_45080272的博客 4710

Java高并发程序设计——无锁

Java高并发程序设计——无锁 一、无锁与有锁区别? 对于并发控制而言,锁是一种悲观的策略。它总是假设每次的临界区的操作会产生冲突,因此,必须对每次操作都小心翼翼。如果有多个线程同时需要访问临界区资源,则宁可牺牲性能让线程进行等待,因此说锁会阻塞线程执行。而无锁是一种乐观的策略,它会假设对资源的访问是没有冲突的。既然没有冲突,自然不需要等待,所以所有的线程都可以在不停顿的状态下持续执行,如果遇到冲...

Tyxxxxxx 421

Java 原子类(AtomicInteger/AtomicReference):无锁并发编程实战

摘要:本文深入探讨Java原子类的核心原理与实战应用,揭示高并发场景下普通变量和synchronized的局限性。通过电商订单统计等真实案例,对比展示AtomicInteger的无锁优势(性能提升4倍),详解CAS机制避免数据失真。重点解析AtomicReference的正确用法,强调必须搭配不可变对象使用。提供生产级代码示例和5大避坑指南,包括ABA问题解决方案。最后总结原子类与锁的适用场景差异,帮助开发者写出高性能线程安全代码。

m0_67391377的博客 804

【实战Java高并发程序设计6】挑战无锁算法

相对于有锁的方法,使用无锁的方式编程更加考验一个程序员的耐心和智力。但是,无锁带来的好处也是显而易见的,第一,在高并发的情况下,它比有锁的程序拥有更好的性能;第二,它天生就是死锁免疫的。就凭借这2个优势,就值得我们冒险尝试使用无锁的并发。

爱上Java8 5058

JAVA高并发——无锁与死锁

CAS、原子类Automic、无锁算法、死锁问题

码说芯语的博客 1324

原子类型:AtomicReference详解

文章目录1 AtomicReferencey引入2 AtomicReference的基本用法2.1 AtomicReference的构造2.2 方法 1 AtomicReferencey引入 AtomicReference类提供了对象引用的非阻塞原子性读写操作,并且提供了其他一些高级的用法 对象的引用其实是一个4字节的数字,代表着在JVM堆内存中的引用地址,对一个4字节数字的读取操作和写入操作本身就是原子性的**,通常情况下,我们对对象引用的操作一般都是获取该引用或者重新赋值(写入操作),我们也没有办法对对

wyaoyao93的博客 4万+
上一篇: JAVA CAS原理深度分析
下一篇: secureCRT端口转发功能突破防火墙限制
zljjava
博客等级 码龄15年 155粉丝 15原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值