setnx是原子操作吗_谈谈Volatile关键字?为什么不能保证原子性?用什么可以替代?为什么?...

fa23b941472cc8e5dfa5efd7f1cdb691.png

大家好,欢迎关注我的公众号码猿bug,需要资料的话可以加我微信好友。

再谈volatile关键字之前,首先必须聊聊JMM内存模型!

JMM主要的特性:可见性、原子性,顺序性

Java 虚拟机规范试图定义一种 Java 内存模型(JMM),来屏蔽掉各种硬件和操作系统的内存访问差异,让 Java 程序在各种平台上都能达到一致的内存访问效果。简单来说,由于 CPU 执行指令的速度是很快的,但是内存访问的速度就慢了很多,相差的不是一个数量级,所以搞处理器的那群大佬们又在 CPU 里加了好几层高速缓存。在 Java 内存模型里,对上述的优化又进行了一波抽象。JMM 规定所有变量都是存在主存中的,类似于上面提到的普通内存,每个线程又包含自己的工作内存,方便理解就可以看成 CPU 上的寄存器或者高速缓存。所以线程的操作都是以工作内存为主,它们只能访问自己的工作内存,且工作前后都要把值在同步回主内存。

网上找的一些定义:

11a514a3943be773e8fab4f3e9b93bfa.png

55c818756b85fc0ddda1773c80e08292.png

简单描述如下:

  • 主存存放线程需要操作的变量,但线程并不直接操作主存。
  • 每个线程读取主存变量都是先拷贝一份到工作内存中,不同线程工作内存互不干扰。
  • 线程修改了工作内存后,再写回主存中。
  • 每次从主存读写的过程都需要经过原子性操作。

简单知道了java的内存模型,那开始聊聊volatile关键字。volatile关键字有三大特性:

①可见性

②不保证原子性

③禁止指令重排

首先要知道volatile是java虚拟机提供的轻量级的同步机制,volatile的可见性是由jvm发送一条lock前缀的汇编指令实现的。volatile关键字是修饰成员变量的,也就是说,如果一个成员变量加了volatile关键字,就会告诉编译器和jvm的内存模型,这个变量是对所有线程共享的,可见性每次JVM都会读取最新写入的值并使其最新值在所有的cpu可见。volatile可以保证线程的可见性并且提供了一定的顺序性,但是无法保证原子性。在JVM底层volatile是采用内存屏障来实现的。使用了volatile关键字就好像是线程直接操作了主内存。

为什么不能保证原子性呢?

在我们的程序中,即使加了volatile也不能保证原子性,有一种粗暴的解决办法,就是加我们的synchronized同步锁,但是这种锁太重了。简单画个图演示为什么不能保证原子性。

在程序中的i++操作,是不能保证原子性的.

8134d1b2a74dd783625ac461ee9b4b2a.png

那原子性和可见性不是就冲突了吗?不冲突

因为volatile 的可见性只能对应l原子性, a=1是原子性,而a++实际上是a=a+1 是非原子性的,所以会导致你说的情况,这时候就要引入同步,强制将a++转化为原子性。

那除了synchronized还有其他解决办法吗?

那就是大名鼎鼎的JUC包下的AtomicInteger,写一小段程序说明:

AtomicInteger 

那为什么用AtomicInteger就能保证原子性呢?因为他的底层是CAS,接下来就要说说什么是cas了。

cas是compare and set的缩写,比较并交换,unsafe是cas的核心类,cas的底层是靠的unsafe类来保证原子性的,unsafe是jvm下的rt.jar的运行jar包里面。

跟进源代码可以看见这段代码:

public final int getAndIncrement(){return unsafe.getAndAddInt(this,1);//这个1是值的valueoffset:内存地址偏移量
}

还靠的是一段do while循环,顾名思义,又叫自旋锁

f6fe1ec31079feefc7175c25d9ec81cc.png

这时候就应该思考,为什么在没有加锁的情况下,还能保证线程安全呢?

①因为atomicInteger借助了UnSafe提供的CAS操作能够保证数据更新的时候是线程安全的,那么为什么借助了unsafe就能保证线程安全呢?以下总结出自我的笔记

4066ca99e4803449c02becebf6cc58a7.png

d64805d8d066655a102dcafa91c57fbe.png

因为cas并发原语体现在JAVA语言中就是sun.misc.Unsafe类中的各个方法。调用Unsafe类中的CAS方法,JVM会帮我们实现汇编指令,这是一种完全依赖的硬件功能。通过他实现了原子操作。并且原语的执行必须是连续的,在执行过程中不允许被中断,也就是说CAS是一条CPU的原子指令,不会造成所谓的数据不一致问题,保证了线程安全。

下一篇文章中会继续讨论CAS的缺点以及volatile的应用场景。技术小白一枚,希望各位大佬指出错误,互相讨论。

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

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

相关文章

360 屏蔽ajax,怎么在easy ui做全局Ajax拦截啊?

满意答案egiuas2014.08.13采纳率:53% 等级:9已帮助:167人在web.xml中定义一个全局过滤器拦截所有请求:自定义filter your difine filter name /* 后台代码:过滤器中获取session用户对象 如果为空,返回超…

用python排序算法_Python - 八大排序算法

1、序言 本文使用Python实现了一些常用的排序方法。文章结构如下: 1.直接插入排序 2.希尔排序 3.冒泡排序 4.快速排序 5.简单选择排序 6.堆排序 7.归并排序 8.基数排序 上述所有的排序均写在一个Python自定义类中,作为成员函数。 2、排序方法详细介绍 1.…

剑指offer-数组中的重复的数字-p39

数组 c中的STL中的vector (STL中的vector每次扩容量时,新的容量都是之前一次的两倍) 在c/c中,数组和指针是相互关联又有区别的两个概念。 关联:当我们声明一个数组时,其数组的名字也是一个指针,该指针指向数组的第一个…

尝鲜!.NET5实操之docker+k8s,这10个坑,你不得不知!

2016年发布了.NET Core第一个正式版本,2020年11月.NET5也正式来临了,技术日新月异,也有点让人应接不暇。在框架设计上,.NET Framework的全家桶理念,培养了一大批的CRUD,而.NET Core转变成了按需使用(Pay fo…

jdk解压版_命令行版的斗地主你玩过没?

相信大家都玩过斗地主游戏,或在现实中斗地主或在电脑和手机上斗地主,但你想过用命令行界面进行斗地主吗?先来张图体验一下:是不是觉得挺有意思,下面就带大家一起玩一下吧~部署命令行版斗地主1 环境准备该项目是基于jav…

c语言——什么时候使用getchar()读取换行符

做题的时候有时会用到getchar()接收换行符,然而让人困惑的是一般使用scanf("%s", str)这样的形式读取字符串的时候似乎并没有考虑这个问题。网上通常会给你讲大道理缓冲区啥的,然后听懂后自己得不得的出结论全看天赋(摊手&#xff…

[项目更新] 集成RabbitMQ队列与EventBus总线

(Blog.Core框架开发情况,着色部分为本次新增)终于项目继续迭代更新了,在开源这两年多,也是感谢每一个支持Blog.Core项目的同学,同时也感谢每一个在生产环境中使用,并提出意见和建议的小伙伴&…

cv2.imread读取图像结果none_python cv2.imread 读取中文路径的图片返回为None的问题

此篇文章首发于我的csdn博客,见原文链接。使用cv2读取图片是常见的事情,但如果,输出图片形状大小时出现报错“ NoneType object has no attribute shape”,后来排查发现读取图片的返回值image为None, 这就说明图片根本…

利用模板化应对ERP业务模型的快速变化

源宝导读:ERP这类复杂系统中,业务模型是系统功能的核心抽象,但业务模型对于不同的客户会有差异,也会随着业务发展而变化。虽然可以对业务组件进行复用,但客户定制的成本依然较高,本文将讨论如何利用模板化应…

mockmvc get请求 tm的 一直404_大家快来看看404的兄弟姐妹

码个蛋(codeegg)第 624 次推文作者:xiaoxiunique博客:https://juejin.im/post/5cd2ea425188254459335583做开发的我们肯定少不了跟网络数据打交道,我们都知道,我们进行网络请求,无论成功还是失败,后台都会给…

网传不要升级.NET5的诸多原因,你赞同几个?

.NET5正式发布有十多天,博客园、知乎、技术群都讨论的非常热烈。关于项目是否迁移.NET5的话题讨论的尤为热烈,作为.NET十年老司机要告诉你,.NET5的迁移势在必行,当下就是最好的时机!犹豫项目是否升级到.NET5的&#xf…

WPF开发的实用小工具 - 快捷悬浮菜单

WPF开发的实用小工具 - 快捷悬浮菜单❝本文由网友投稿,Dotnet9站长整理。站长觉得这小工具很实用,站长家里、公司也在尝试使用了。行文目录:这工具有什么用?正文源码获取及应用下载体验站长的建议1. 这工具有什么用?问…

accdb原有的数据怎么清除_VBA中利用数组对数据批量处理的方法

大家好,今日继续和大家分享VBA编程中常用的常用"积木"过程代码。这些内容大多是我的经验和记录,来源于我多年的经验。今日分享的是NO.225-NO.226,内容是:NO. 225:数组的赋值和回填工作表NO. 226:…

云南河道 kml文件_处理能力提升 4 倍 ,大疆智图 4 天完成 5 公里河道建模

马陵河是江苏省宿迁市老城区一条重要排涝河道,1974 年人工开挖而成,全长 5.2 km,汇水面积 11.6 km,居住人口 13.85 万人。河道水质长期处于黑臭状态,严重影响周边居民日常生活,被称为宿迁的“龙须沟”。宿迁…

linq 查询的结果会开辟新的内存吗?

一:背景 1. 讲故事昨天群里有位朋友问:linq 查询的结果会开辟新的内存吗?如果开了,那是对原序列集里面元素的深拷贝还是仅仅拷贝其引用?其实这个问题我觉得问的挺好,很多初学 C# 的朋友或多或少都有这样的疑…

问题 B: 十进制到二进制的转换

这个问题我们来用栈来实现 首先,我们先定义一个栈的结构体(栈的结构体与链表的结构体不可同,栈的结构体第二项是用int定义栈的顶端; 而链表的第二项,是用struct定义一个指针) struct stack{int data[10005];int top;…

javascript内存泄漏调试工具mac_node.js 内存泄漏的秘密

一直以来,跟踪 Node.js 的内存泄漏是一个反复出现的话题,人们始终希望对其复杂性和原因了解更多。并非所有的内存泄漏都显而易见。但是,一旦我们确定了其模式,就必须在内存使用率,内存中保存的对象和响应时间之间寻找关…

Leansoft再发招贤令:面试官徐磊有话讲 | IDCF

(图片来源于网络)2020是Leansoft成立的第五年,凭借专业的服务及实施能力,逐渐成长为国内唯一的端到端专业DevOps实施服务公司。Leansoft是一家怎样的公司呢?准确地说,我们其实是国内唯一一家提供端到端的De…

问题 B: 数塔问题

题目描述 有如下所示的数塔&#xff0c;要求从顶层走到底层&#xff0c;若每一步只能走到相邻的结点&#xff0c;则经过的结点的数字之和最大是多少&#xff1f; 输入 第一行是一个整数N(1 < N < 20)&#xff0c;表示数塔的高度&#xff0c;接下来用N个数字表示数塔&a…

e盾服务端源码_gRPC服务注册发现及负载均衡的实现方案与源码解析

今天聊一下gRPC的服务发现和负载均衡原理相关的话题&#xff0c;不同于Nginx、Lvs或者F5这些服务端的负载均衡策略&#xff0c;gRPC采用的是客户端实现的负载均衡。什么意思呢&#xff0c;对于使用服务端负载均衡的系统&#xff0c;客户端会首先访问负载均衡的域名/IP&#xff…