AtomicInteger原理和CAS与Synchronized(juc编程)
AtomicInteger原理
4.6.1 原理介绍
AtomicInteger的本质:自旋锁 + CAS算法
CAS的全成是: Compare And Swap(比较再交换); 是现代CPU广泛支持的一种对内存中的共享数据进行操作的一种特殊指令。CAS可以将read-modify-write转换为原子操作,这个原子操作
直接由处理器保证。CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当旧预期值A和内存值V相同时,将内存值V修改为B并返回true,否则什么都不做,并返回false。
举例说明:
-
在内存值V当中,存储着值为10的变量。

-
此时线程1想要把变量的值增加1。对线程1来说,旧的预期值 A = 10 ,要修改的新值 B = 11。

-
在线程1要提交更新之前,另一个线程2抢先一步,把内存值V中的变量值率先更新成了11。

-
线程1开始提交更新,首先进行A和内存值V的实际值比较(Compare),发现A不等于V的值,提交失败。

-
线程1重新获取内存值V作为当前A的值,并重新计算想要修改的新值。此时对线程1来说,A = 11,B = 12。这个重新尝试的过程被称为自旋。

-
这一次比较幸运,没有其他线程改变V的值。线程1进行Compare,发现A和V的值是相等的。

-
线程1进行SWAP,把内存V的值替换为B,也就是12。

举例说明:这好比春节的时候抢火车票,下手快的会抢先买到票,而下手慢的可以再次尝试,直到买到票。
4.6.2 源码分析
那么接下来我们就来查看一下AtomicInteger类中incrementAndGet方法的源码。
public class AtomicInteger extends Number implements java.io.Serializable {// cas算法的实现类private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();// 表示变量值在内存中的偏移量地址,unsafe类就是根据内存偏移量地址获取数据值。private static final long VALUE = U.objectFieldOffset(AtomicInteger.class, "value");private volatile int value;// 以原子方式将当前值加1,这里返回的是自增后的值public final int incrementAndGet() {/* this表示当前AtomicInteger对象 ,1表示要增加的值 */return U.getAndAddInt(this, VALUE, 1) + 1; // 调用Unsafe类中的getAndAddInt方法}}
UnSafe类
public final class Unsafe {// Unsafe类中的getAndAddInt方法public final int getAndAddInt(Object o, long offset, int delta) {int v;// do...while就是自旋操作,当CAS成功以后,循环结束do {// 获取AtomicInteger类中所封装的int类型的值,就相当于旧的预期值Av = getIntVolatile(o, offset); // 调用本类的weakCompareAndSetInt方法实现比较在交换; o: AtomicInteger对象, v: 相当于旧的预期值A, v + delta:新值B} while (!weakCompareAndSetInt(o, offset, v, v + delta));return v;}// Unsafe类中的weakCompareAndSetInt方法public final boolean weakCompareAndSetInt(Object o, long offset, int expected, int x) {return compareAndSetInt(o, offset, expected, x);}// 本地方法,调用CPU指令实现CASpublic final native boolean compareAndSetInt(Object o, long offset, int expected, int x);}
4.7 CAS与Synchronized
CAS和Synchronized都可以保证多线程环境下共享数据的安全性。那么他们两者有什么区别?
Synchronized是从悲观的角度出发:
总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线
程阻塞,用完后再把资源转让给其它线程)。因此Synchronized我们也将其称之为悲观锁。jdk中的ReentrantLock也是一种悲观锁。
CAS是从乐观的角度出发:
总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据。CAS这种机制我们也可以将其称之为乐观锁。
相关文章:
AtomicInteger原理和CAS与Synchronized(juc编程)
AtomicInteger原理 4.6.1 原理介绍 AtomicInteger的本质:自旋锁 CAS算法 CAS的全成是: Compare And Swap(比较再交换); 是现代CPU广泛支持的一种对内存中的共享数据进行操作的一种特殊指令。CAS可以将read-modify-write转换为原子操作,这…...
抖音a_bogus,mstoken全参数爬虫逆向补环境2024-06-15最新版
抖音a_bogus,mstoken全参数爬虫逆向补环境2024-06-15最新版 接口及参数 打开网页版抖音,右键视频进入详情页。F12打开控制台筛选detail,然后刷新网页,找到请求。可以发现我们本次的参数目标a_bogus。a_bogus有时长度为168有时为172…...
【机器学习】机器学习重要方法—— 半监督学习:理论、算法与实践
文章目录 引言第一章 半监督学习的基本概念1.1 什么是半监督学习1.2 半监督学习的优势 第二章 半监督学习的核心算法2.1 自训练(Self-Training)2.2 协同训练(Co-Training)2.3 图半监督学习(Graph-Based Semi-Supervise…...
leetcode70 爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 示例 1: 输入:n 2 输出:2 解释:有两种方法可以爬到楼顶。 1. 1 阶 1 阶 2. 2 阶 示例 2&#x…...
ENVI实战—一文搞定非监督分类
实验1:使用isodata法分类 目的:学会使用isodata法开展非监督分类 过程: ①导入影像:打开ENVI,按照“文件→打开为→光学传感器→ESA→Sentinel-2”的顺序,打开实验1下载的哨兵2号数据。 图1 ②区域裁剪…...
【Qt 学习笔记】Qt系统相关 | Qt事件 | 事件的介绍及基本概念
博客主页:Duck Bro 博客主页系列专栏:Qt 专栏关注博主,后期持续更新系列文章如果有错误感谢请大家批评指出,及时修改感谢大家点赞👍收藏⭐评论✍ Qt系统相关 | Qt事件 | 事件的介绍及基本概念 文章编号:Qt…...
具身智能特点及实现路线
多模态——多功能的“小脑” 人类具有眼耳鼻舌身意,说明对于物理世界的充分感知和理解,是意识和智慧的来源。而传统AI更多的是被动观测,主要是“看”(计算机视觉)和“读”(文本NLP),…...
重温react-04
兄弟组件之间通信 兄弟1 import React, { Component } from react import pubsub from ./pubsub export default class learnReact01 extends Component {render() {return (<div>我是兄弟1<button onClick{this.clickMessage}>向兄弟2发信息</button><…...
lock-锁的概念
锁的简介 锁是计算机协调多个进程或线程并发访问某一资源的机制(避免发生资源争抢) 在并发环境下,多个线程会对同一个资源进行争抢,可能会导致数据不一致的问题。为了解决这一问题,需要通过一种抽象的锁来对资源进行…...
Docker 可用镜像源
当使用 docker 发现拉取不到镜像时,可以编辑 /etc/docker/daemon.json 文件,添加如下内容: 这文章不涉及政治,不涉及敏感信息,三番五次的审核不通过,一删再删,只好换图片了。 重新加载服务配置…...
MySQL 搭建主从报错 1236
错误信息: Last_IO_Error: Got fatal error 1236 from source when reading data from binary log: Could not find first log file name in binary log index file 大致内容: MySQL 在尝试从二进制日志(binary log)中读取数据…...
华为OD机试真题2024版-求幸存数之和
题目描述\n给一个正整数列 nums,一个跳数 jump,及幸存数量 left。运算过程为:从索引为 0 的位置开始向后跳,中间跳过 J 个数字,命中索引为 J+1 的数字,该数被敲出,并从该点起跳,以此类推,直到幸存 left 个数为止。然后返回幸存数之和。\n约束: 1、0 是第一个起跳点。…...
Python - 各种计算器合集【附源码】
计算器合集 一:极简版计算器二:简易版计算器三:不简易的计算器四:还可以计算器 一:极简版计算器 运行效果: import tkinter as tk import tkinter.messagebox win tk.Tk() win.title("计算器")…...
【已解决】better-scroll在PC端如何开启鼠标滚动以及如何始终显示滚动条
总结 需要安装插件 mouse-wheel 和 scrollbar 在PC端如何开启鼠标滚动? 需要安装官方提供的滚动插件:mouse-wheel https://better-scroll.github.io/docs/zh-CN/plugins/mouse-wheel.html 为了开启鼠标滚动功能,你需要首先引入 mouseWheel 插件&…...
AJAX 综合案例-day2
Bootstrap 弹框 功能:不离开当前页面,显示单独内容,供用户操作 步骤: 1. 引入 bootstrap.css 和 bootstrap.js 2. 准备 弹框标签 ,确认结构 3. 通过 自定义属性 ,控制弹框的 显示 和 隐藏 1. 通过属性…...
【Esp32连接微信小程序蓝牙】附Arduino源码《 返回10007 相同特征id冲突问题》
前言 最近接了一个外包,发现了esp32连接小程序会有很多bug,所以接下来会慢慢更新解决方案,还是需要多接触项目才能进步呀兄弟们! 附上uuid的生成链接: // See the following for generating UUIDs: // https://www.uu…...
并发控制技术
事物的隔离性实现主要依赖于多种并发控制技术,这些技术确保在并发执行的事物中,一个事物的操作不会被其他事物干扰。并发控制技术按照其对可能冲突的操作采取的不同策略可以分为乐观并发控制和悲观并发控制两大类。 基于封锁的并发控制 对于并发可能冲突的操作,比如读-写,…...
什么是网段
一、A类地址的网段: 情况1:最小的网段就是xxx.0.0.0,直接使用第一段的网络地址做网段。 情况2:如果希望网段允许的主机数量的范围缩小,扩大网段值即可,xxx.xxz.zzz.zzz,比如xxx.xxx.xzz.zzz&…...
PHP和Mysql前后端交互效果实现
一、连接数据库基本函数 mysqli_connect(); 作用:创建数据库连接,打开一个新的mysql的连接。传参顺序:数据库地址、数据库账号、数据库密码 <?phpecho mysqli_connect("localhost",root,root) ?> /*结果:F…...
vue小总结
知识总结 【 1 】es6 语法总结 # let 定义变量 # const定义常量 ------块级作用域---- # var 以后尽量少用,函数作用域var 在 JavaScript 中是函数作用域或全局作用域。而 let 和 const 是块级作用域。 // 使用 var 声明全局变量 var globalVar "Im a globa…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...
Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...
【位运算】消失的两个数字(hard)
消失的两个数字(hard) 题⽬描述:解法(位运算):Java 算法代码:更简便代码 题⽬链接:⾯试题 17.19. 消失的两个数字 题⽬描述: 给定⼀个数组,包含从 1 到 N 所有…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
