07JVM_内存模型和CAS与原子类

一、内存模型

1.java内存模型

Java内存结构是JMM(Java Memory Model)的意思。JMM定义了一套在多线程读写共享数据(成员变量,数组)时,对数据的原子性,见性,有序性的规则和保障。

1.1 原子性

什么是原子性?

原子性是指一个操作是不可中断的,即使多个线程一起执行,一个线程一旦开始,就不会被其他线程干扰。

如何保证原子性

①synchronized(同步关键字)

java 复制代码
synchronized(对象){

  原子操作代码

}

从第一个线程开始,给这个对象加锁,可以安全执行原子操作代码。其他线程需要排队等候

用synchronized解决并发问题

②各种Lock

synchronized 和各种 Lock 可以保证任一时刻只有一个线程访问该代码块,因此可以保障原子性

1.2 可见性

什么是可见性?

可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。

如何保证可见性

在 Java 中,可以借助synchronized、volatile 以及各种 Lock 实现可见性。如果我们将变量声明为 volatile ,这就指示 JVM,这个变量是共享且不稳定的,每次使用它都到主存中进行读取。

volatile

修饰成员变量和静态成员变量,避免线程从自己的工作缓存查找变量的值,必须到主存获取它的值,线程操作volatile变量都是直接操作主存

1.3有序性

什么是有序性?

①由于指令重排序问题,代码的执行顺序未必就是编写代码时候的顺序。

②指令重排序可以保证串行语义一致,但是没有义务保证多线程间的语义也一致 ,所以在多线程下,指令重排序可能会导致一些问题。

③在Java中,volatile关键字可以禁止指令进行重排序优化

2.happens-before

介绍

happens-before规定哪些写操作对其他线程的读操作可见。是可见性与有序性的一套规则。

如何保证

①volatile

②synchronized

二、CAS与原子类

1.CAS无锁并发概述

1.介绍

①CAS全称compare and swap比较并交换

②当多个线程同时操作同一个资源,只能有一个线程操作成功。但是不会阻塞其他线程,其他线程只会收到操作失败的信号。

③CAS是一个乐观锁

补充

乐观锁:认为数据在一般情况下不会产生冲突,所以在数据提交更新的时候,才会对数据是否产生并发冲突进行检测,如果发现并发冲突,则返回错误信息,返回的错误信息可以根据自己的业务进行处理

悲观锁:总是假设最坏的情况,每次在获取共享数据的时候,都认为别人会修改,所以每次都在获取数据的时候加锁。共享资源每次只会给一个线程使用,其他线程阻塞,用完再把资源给其他线程

2.工作流程

读写的内存值V

进行比较的值A

需要写入的新值B

①内存中的原数据V,旧值A,修改的新值B。

②比较A与V是否相等

③如果相等,将B写入V(交换)

④返回操作是否成功

3.代码分析

多个线程对一个共享的整型变量执行+1操作

①CAS不加锁,使用while(true)死循环不管尝试/

②共享变量是从内存读取的,所以保证变量的可见性。使用volatile修饰

③调用compareAndSwap(旧值,新值)进行比较。

④compareAndSwap操作成功,退出循环。

⑤compareAndSwap操作失败,说明其他线程把这个共享变量修改了。需要再次循环读取

注意:

①CAS和volatile结合实现无锁并发,适用竞争不激烈,多核CPU(循环重试)

②竞争激烈,重试频繁发生,降低效率

③没有使用用synchronized,线程不会阻塞,提升效率。

4.CAS的缺点

①ABA问题,CAS更新操作的时候检查内存值是否变化,没有变化更新内存值。如果原来内存值A,后来变成B,然后再变回A。出现ABA问题,CAS检查没有变化,实际变化了。解决方法就是变量前面加一个版本号,每次更新版本号加1。这样变化成了1A2B3A

②循环时间长,开销大。CAS操作长时间不成功,会导致一直循环。CPU开销大

③只保证一个共享变量的原子操作。对一共享变量执行操作时,CAS能够保证原子操作,但对多个共享变量操作时,CAS无法保证操作的原子性。

2.CAS底层实现

介绍

CAS底层是依赖一个Unsafe类直接调用操作系统底层的CAS指令。

调用UnSafe类中的CAS方法,JVM会帮我们实现出CAS汇编指令

部分代码

java 复制代码
public final boolean compareAndSet(int expect, int update) {

        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);

}

参数说明

this Unsafe对象

valueOffset 共享变量的地址

expect 旧值

update 新值

如果原子变量中的 value 值等于 expect,则使用 update 值更新该值并返回 true,否则返回 false。

3.原子操作类

juc提供原子操作类,可以提供线程安全的操作。AtomicInteger,AtomicBoolean。底层实现是CAS+volatile实现

相关推荐
带刺的坐椅3 分钟前
Solon v3.4.7, v3.5.6, v3.6.1 发布(国产优秀应用开发框架)
java·spring·solon
四谎真好看1 小时前
Java 黑马程序员学习笔记(进阶篇18)
java·笔记·学习·学习笔记
桦说编程2 小时前
深入解析CompletableFuture源码实现(2)———双源输入
java·后端·源码
java_t_t2 小时前
ZIP工具类
java·zip
lang201509282 小时前
Spring Boot优雅关闭全解析
java·spring boot·后端
pengzhuofan3 小时前
第10章 Maven
java·maven
百锦再3 小时前
Vue Scoped样式混淆问题详解与解决方案
java·前端·javascript·数据库·vue.js·学习·.net
刘一说4 小时前
Spring Boot 启动慢?启动过程深度解析与优化策略
java·spring boot·后端
壹佰大多4 小时前
【spring如何扫描一个路径下被注解修饰的类】
java·后端·spring
百锦再4 小时前
对前后端分离与前后端不分离(通常指服务端渲染)的架构进行全方位的对比分析
java·开发语言·python·架构·eclipse·php·maven