学习系列之并发编程(四)

『死磕Java并发编程系列』并发编程工具类之CountDownLatch 《死磕 Java 并发编程》系列连载中,大家可以关注一波: ????????『死磕Java并发编程系列』 01 十张图告诉你多线程那些破事 『死磕Java并发编程系列』 02 面试官:说说什么是Java内存模型? 『死磕Java并发编程系列』 03 面试必问的CAS原理你会了吗? 『死磕Java并发编程系列』 04 面试官:说说Atomic原子类的实现原理? ????????『死磕Java并发编程系列』 05 图解Java中那18 把锁 在日常编码中,Java 并发编程可是少不了,试试下面这些并 阅读详情

CAS

1、什么是CAS?

CAS:Compare and Swap,即比较再交换。
java.util.concurrent.*,其下面的类使用CAS算法实现了区别于synchronouse同步锁的一种乐观锁。CAS是一种无锁算法,CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。
举例:

public class CASTest {
    public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(111222);
        //预期达到就更新,否则不更新
        System.out.println(atomicInteger.compareAndSet(111222, 222111));//true
        System.out.println(atomicInteger.get());//222111
    }
}

查看compareAndSet源码,

    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long valueOffset;
    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

会发现一个Unsafe类。

2.Unsafe类

Unsafe类存在于sun.misc包中,其内部方法操作可以像C的指针一样直接操作内存,单从名称看来就可以知道该类是非安全的,毕竟Unsafe拥有着类似于C的指针操作,因此总是不应该首先使用Unsafe类,Java官方也不建议直接使用的Unsafe类。
Java中CAS操作的执行依赖于Unsafe类的方法,Unsafe类中的所有方法都是native修饰的,也就是说Unsafe类中的方法都直接调用操作系统底层资源执行相应任务,关于Unsafe类的主要功能点如下(参考):

内存管理,Unsafe类中存在直接操作内存的方法;
 
//分配内存指定大小的内存
 
public native long allocateMemory(long bytes);
 
 
//根据给定的内存地址address设置重新分配指定大小的内存
 
public native long reallocateMemory(long address, long bytes);
 
 
//用于释放allocateMemory和reallocateMemory申请的内存
 
public native void freeMemory(long address);
 
 
//将指定对象的给定offset偏移量内存块中的所有字节设置为固定值
 
public native void setMemory(Object o, long offset, long bytes, byte value);//设置给定内存地址的值public native void putAddress(long address, long x);
 
 
//获取指定内存地址的值
 
public native long getAddress(long address);
 
 
//设置给定内存地址的long值
 
public native void putLong(long address, long x);
 
 
//获取指定内存地址的long值
 
public native long getLong(long address);
 
 
//设置或获取指定内存的byte值
 
//其他基本数据类型(long,char,float,double,short等)的操作与putByte及getByte相同
 
public native byte getByte(long address);
 
public native void putByte(long address, byte x);
 
 
//操作系统的内存页大小
 
public native int pageSize();
 
 
提供实例对象新途径:
 
//传入一个对象的class并创建该实例对象,但不会调用构造方法
 
public native Object allocateInstance(Class cls) throws InstantiationException;
 
 
类和实例对象以及变量的操作,还有很多,就不贴出来了
 
 
//传入Field f,获取字段f在实例对象中的偏移量
 
//获得给定对象偏移量上的int值,所谓的偏移量可以简单理解为指针指向该变量的内存地址,
 
//通过偏移量便可得到该对象的变量
 
//通过偏移量可以设置给定对象上偏移量的int值
 
//获得给定对象偏移量上的引用类型的值
 
//通过偏移量可以设置给定对象偏移量上的引用类型的值
 
虽然在Unsafe类中存在getUnsafe()方法,但该方法只提供给高级的Bootstrap类加载器使用,普通用户调用将抛出异常,所以我们在Demo中使用了反射技术获取了Unsafe实例对象并进行相关操作。

3.原子操作类(Atomic)

原子更新基本类型主要包括3个类:
AtomicBoolean:原子更新布尔类型
AtomicInteger:原子更新整型
AtomicLong:原子更新长整型
原子更新引用数据类型主要包括:
AtomicReference 原子操作引用对象类型

以AtomicInteger原子类为例:(参考):

public class AtomicInteger extends Number implements java.io.Serializable {
    private static final long serialVersionUID = 6214790243416807050L;
 
    // 获取指针类Unsafe
    private static final Unsafe unsafe = Unsafe.getUnsafe();
 
    //下述变量value在AtomicInteger实例对象内的内存偏移量
    private static final long valueOffset;
 
    static {
        try {
           //通过unsafe类的objectFieldOffset()方法,获取value变量在对象内存中的偏移
           //通过该偏移量valueOffset,unsafe类的内部方法可以获取到变量value对其进行取值或赋值操作
            valueOffset = unsafe.objectFieldOffset
                (AtomicInteger.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }
   //当前AtomicInteger封装的int变量value
    private volatile int value;
 
    public AtomicInteger(int initialValue) {
        value = initialValue;
    }
    public AtomicInteger() {
    }
   //获取当前最新值,
    public final int get() {
        return value;
    }
    //设置当前值,具备volatile效果,方法用final修饰是为了更进一步的保证线程安全。
    public final void set(int newValue) {
        value = newValue;
    }
    //最终会设置成newValue,使用该方法后可能导致其他线程在之后的一小段时间内可以获取到旧值,有点类似于延迟加载
    public final void lazySet(int newValue) {
        unsafe.putOrderedInt(this, valueOffset, newValue);
    }
   //设置新值并获取旧值,底层调用的是CAS操作即unsafe.compareAndSwapInt()方法
    public final int getAndSet(int newValue) {
        return unsafe.getAndSetInt(this, valueOffset, newValue);
    }
   //如果当前值为expect,则设置为update(当前值指的是value变量)
    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }
    //当前值加1返回旧值,底层CAS操作
    public final int getAndIncrement() {
        return unsafe.getAndAddInt(this, valueOffset, 1);
    }
    //当前值减1,返回旧值,底层CAS操作
    public final int getAndDecrement() {
        return unsafe.getAndAddInt(this, valueOffset, -1);
    }
   //当前值增加delta,返回旧值,底层CAS操作
    public final int getAndAdd(int delta) {
        return unsafe.getAndAddInt(this, valueOffset, delta);
    }
    //当前值加1,返回新值,底层CAS操作
    public final int incrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
    }
    //当前值减1,返回新值,底层CAS操作
    public final int decrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
    }
   //当前值增加delta,返回新值,底层CAS操作
    public final int addAndGet(int delta) {
        return unsafe.getAndAddInt(this, valueOffset, delta) + delta;
    }
   //省略一些不常用的方法....
}

挑选getAndIncrement()进行分析

public final int getAndIncrement() {
        return unsafe.getAndAddInt(this, valueOffset, 1);
    }
    public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            var5 = this.getIntVolatile(var1, var2);
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

        return var5;
    }
public native int getIntVolatile(Object var1, long var2);
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

getAndIncrement()去调用getAndAddInt(),参数一一对应匹配,native方法是java调用c++时所使用的本地方法,c++可以直接操作内存,do while自旋锁操作,AtomicInteger类中所有自增或自减的方法都间接调用Unsafe类中的getAndAddInt()方法实现了CAS操作,从而保证了线程安全。

4.CAS的问题

1.循环耗时,会给CPU带来很大的时间开销。
2.会导致ABA问题。
3.一次性只能保证一个共享变量的原子操作。

学习《Java并发编程》目录索引 (持续更新中)      写在前面:此系列为本人学习黑马《Java并发编程》所整理的笔记 ! 不局限于应用层开发, 更加深入理解多线程, 并发编程, 更有利于我们长久发展 ! 学习Java并发编程 阅读详情

相关推荐

Mac微信聊天记录备份终极指南:用软链接轻松迁移到外接硬盘(附重签名教程)

本文详细介绍了如何通过软链接技术将Mac微信聊天记录备份迁移到外接硬盘,解决内置存储空间不足的问题。教程包括备份文件定位、软链接创建及微信重签名步骤,帮助用户高效管理微信数据,释放Mac存储空间。

uuu88的博客 1163

并发编程系列(七)—原子类框架Atomic剖析

大家好,牧码心今天给大家推荐一篇并发编程系列(七)—原子类框架Atomic剖析的文章,希望对你有所帮助。

牧码心 548

Android7以上抓取https数据包-无需root

手机内装一个虚拟机,然后在虚拟机内运行我需要抓包的应用,该虚拟机内是不需要证书验证的。完美解决android7.0以上https无法抓包的问题。

qq_45764684的博客 1454

高并发编程_高并发编程【无锁篇】

摘要:本文首先通过讲解无锁的原理,以及为何选用无锁实现原子操作,在此基础上,介绍几个无锁原子操作代表类:AtomicInteger、AtomicReference、AtomicStampedReference、AtomicIntegerArray、AtomicIntegerFieldUpdater。1. 无锁类的原理1.1. 概述根据【概念理解篇】可以知道,无锁是基于无障碍的,无障碍指的是所有线程...

weixin_35779506的博客 555

PyCharm配置WSL开发环境保姆级教程:从安装Conda到项目依赖一键搞定

本文提供PyCharm配置WSL开发环境的完整教程,涵盖从安装Conda到项目依赖管理的全流程。详细介绍了WSL2环境准备、Conda环境配置、PyCharm远程解释器设置等关键步骤,并包含实用技巧和常见问题解决方案,帮助开发者高效搭建Python开发环境。

weixin_42620202的博客 307

在ubuntu20.04上配置VINS_Fusion(亲测有效,一应俱全)

最近在做科研训练的时候配置了HKUST-Aerial-Robotics实验室的VINS_Fusion代码项目,经历了一些编译报错的问题,在网上查找的时候博客内容良莠不齐,且实质针对性意见不多,于是在此记录下自己配置期间遇到的一些共性问题,留作自己日后参考和大家的交流学习。

wyr1849089774的博客 8266

Unsafe类中的compareAndSwapInt(Object var1, long var2, int var4, int var5)参数解释

public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5); var1:要修改的对象起始地址 如:0x00000111 var2:需要修改的具体内存地址 如100 。0x0000011+100 = 0x0000111就是要修改的值的地址 注意没有var3 var4:期望内存中的值,拿这个值和0x0000111内存中的中值比较,如果为true,则修改,返回ture,否则返回false,等

前路无畏的博客 1万+

使用MATLAB结合EasySpin进行ESR模拟的详细步骤及示例代码

安装EasySpin:确保你已经安装了EasySpin工具箱,它可以帮助你进行ESR模拟。你可以从EasySpin的官方网站(https://easyspin.org/)下载并安装。准备实验数据:将实验得到的EPR数据整理成合适的格式,一般包含磁场(Magnetic Field)和信号强度(Intensity)两列。进行模拟:使用EasySpin的函数对单线态氧自由基和超氧自由基进行模拟。调整参数:通过调整模拟参数,使模拟得到的峰型和峰位置与实验数据尽可能匹配。导出数据。

AI的内部世界的博客 2004

CAS原理

像synchronized这种独占锁属于悲观锁,它是在假设一定会发生冲突的,那么加锁恰好有用,除此之外,还有乐观锁,乐观锁的含义就是假设没有发生冲突,那么我正好可以进行某项操作,如果要是发生冲突呢,那我就重试直到成功,乐观锁最常见的就是CAS。 我们在读Concurrent包下的类的源码时,发现无论是ReenterLock内部的AQS,还是各种Atomic开头的原子类,内部都应用到了CAS,最常见...

weixin_33754913的博客 194

SAP SD销售订单的ATP检查简介

如果可用性检查组设置为01(汇总需求),系统将更新销售订单需求到汇总表VBBS,该表中未记录销售订单号码,因此在MD04中不会显示销售订单号码,而是按天汇总显示销售需求。如果物料的可用性检查组设置为02(单个需求),系统将更新销售订单需求到表VBBE,该表中记录了销售订单号码,因此在MD04显示销售订单的号码以及需求,前面的文章中我们解释了PP模块中的ATP检查,也解释了MM模块中的ATP的检查,本文将说明一下SD模块中的ATP检查。可用性检查用的最多的就是02,有兴趣的同学可以测试一下可用性检查01。

我小时候很黑的博客 4291

知识图谱中的 Ontology(本体论)

1980年,本体论(Ontology)哲学概念“本体”被引入到人工智能领域用来刻画知识。本体概念模型、明确、形式化、共享。本体是实体存在形式的描述,往往表示为一组概念定义和概念之间的层级关系,本体框架形式树状结构,通常被用来为知识图谱定义schema。如人、公司、车等都可以在具体场景下称为本体。Ontology是(特定领域)信息组织的一种形式,是领域知识规范的抽象和描述,是表达、共享、重用知识的方法。Ontology。

全网粉丝30W+,优快云、稀土掘金人工智能领域签约作者,人工智能、大模型、Python 爬虫,商务合作,请私信沟通。 2028

Java中GetAndAdd函数

GetAndAdd解释

gong_yangyang的博客 1万+

解决开着代理情况下pip或魔搭下载失败

最近由于经常配环境导致,老是要来回切clash关掉代理,非常的不方便如下面的,魔搭模型下载失败如下面的,pip换源后下载失败。

风吹落叶的博客 2949

【Go语言学习系列31】并发编程(四):sync包

详细介绍Go语言sync包提供的各种同步原语,包括Mutex、RWMutex、WaitGroup等工具的使用方法、最佳实践及常见问题,帮助你有效控制并发程序中的共享资源访问

GopherTribe的博客 1068

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Java并发编程学习系列四:线程池

概念 为什么要使用多线程呢? 先从总体上来说: 从计算机底层来说:线程可以比作是轻量级的进程,是程序执行的最小单位,线程间的切换和调度的成本远远小于进程。另外,多核 CPU 时代意味着多个线程可以同时运行,这减少了线程上下文切换的开销。 从当代互联网发展趋势来说:现在的系统动不动就要求百万级甚至千万级的并发量,而多线程并发编程正是开发高并发系统的基础,利用好多线程机制可以大大提高系统整体的并发能力以及性能。 再深入到计算机底层来探讨: 单核时代: 在单核时代多线程主要是为了提高 CPU 和 IO 设备

Herishwater的博客 502

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

深入学习掌握JUC并发编程系列(四) -- 深入剖析Java内存模型

深入学习掌握JUC并发编程系列(四) -- 深入剖析Java内存模型

snapepotter的博客 173

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

JAVA工程师学习路线

JAVA工程师学习路线 第一阶段 1.Java基础(JavaSE) 2.HTML+CSS+JavaScript 3.MySQL 第二阶段 1.Java进阶 2.JS+JQuery+Ajax 3.数据库 第三阶段 1.JavaWeb 2.软件工程 3.Git、Linux、软件测试 第四阶段 1.深入理解Java虚拟机 2.设计模式相关书籍 3.Http协议相关书籍 4.Java并发,多线程,网络编程...

sk18192449347的博客 979

【Go语言学习系列29】并发编程(二):channel基础

深入讲解Go语言channel的核心概念、使用方法与最佳实践,包括缓冲与非缓冲通道、发送接收操作、关闭通道等重要知识点,助您全面掌握Go并发编程的核心机制

GopherTribe的博客 997

【Python系列】Python 并发编程概述

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。💝💝💝 ✨✨ 欢迎订阅本专栏 ✨✨。

优快云站内信: https://i.youkuaiyun.com/#/msg/chat/qyj19920704 3万+

如何学习Java并发编程

2012年我刚转行到互联网,那年夏天我从传统通信行业跳槽到互联网行业。那是我成年后看的第一部国产动画片,可谓惊为天人。里面有所谓的八奇技,其中有一门绝技称为:术之尽头,炁体源流。虽然目前作者还没有揭开谜底,但从定义上来说,炁体源流大概有“追本溯源,回归本质”的含义。为什么扯这些呢?很多人学不好Java并发编程,恰恰是因为没有抓住本质。

smart_an的专栏 1484

我用10张图总结出了这份并发编程最佳学习路线!!(建议收藏)

冰河用10张图总结出了这份并发编程最佳学习路线,强烈建议大家收藏!!

冰河的专栏 9800

并发编程系列之并发编程的认识

前言 今天我们开始接触并发编程的讲解,首先我们要知道并发编程的目的是什么?一个目的,为了让程序员运行的更快,但是有一点我们要知道,并不是启动越多的线程就能让程序更大限度的并发执行,在并发编程的开发中,如果希望使用更多的线程来加快程序的运行,一般我们会面临下面几种挑战:上下文切换问题,死锁、以及受硬件和软件资源的限制问题,那么我们一个个来说下吧,让我们开始今天的并发编程之旅吧。 上下文切换 什么是上下文切换? 即使是单核处理器,也支持多线程执行代码,CPU通过给每个线程分配CPU时间片来实现这个机

吭哧吭哧快乐的小牛码 2万+

并发编程系列(四) -volatile关键字介绍

在上篇文章中,我们介绍到在多线程环境下,如果编程不当,可能会出现程序运行结果混乱的问题。出现这个原因主要是,JMM 中主内存和线程工作内存的数据不一致,以及多个线程执行时无序,共同导致的结果。

程序员志哥的博客 1071

并发编程系列——wait原理的讨论(1)

这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 欢迎使用Markdown编辑器 你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Mar

java_lyvee的专栏 9318

【Go语言学习系列33】并发编程(六):原子操作与内存模型

深入探讨Go语言的原子操作和内存模型,包括sync/atomic包的应用、happens-before关系、内存重排以及并发陷阱的避免方法,帮助你构建高效、正确的并发程序

GopherTribe的博客 1208

Java并发编程面经大全——双非上岸阿里巴巴系列

双非本科,四面成功上岸阿里巴巴,在这里把自己整理的面经分享出来,欢迎大家阅读。 序号 文章名 超链接 1 操作系统面经大全——双非上岸阿里巴巴系列 2021最新版面经——>传送门1 2 计算机网络面经大全——双非上岸阿里巴巴系列 2021最新版面经——>传送门2 3 Java并发编程面经大全——双非上岸阿里巴巴系列 2021最新版面经——>传送门3 4 面试阿里,你必须知道的背景知识——双非上岸阿里巴巴系列 2021最新版面经——>传送门4 如有疏漏

weixin_43899069的博客 3639
上一篇: 学习系列之并发编程(三)
下一篇: MySQL中删除重复数据要求最终只保留一条
CodersCoder
博客等级 码龄10年 90粉丝 258原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值