IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> JMM---Volatile关键字 -> 正文阅读

[Java知识库]JMM---Volatile关键字

JMM
????????即Java Memory Model 它定义了主存、工作内存抽象概念,底层对应着CPU寄存器、缓存、硬件内存、CPU指令优化等

JMM体现在以下几个方面
????????·原子性-保证指令不会受到线程上下文切换的影响

????????????????synchronized和Lock能够保证任一时刻只有一个线程执行该代码块,那么自然就不存在原子性问题了,从而保证了原子性。
? ? ? ? ·可见性-保证指令不会受cpu缓存的影响
????????????????volatile关键字可以保证可见性
? ? ? ? ·有序性-保证指令不会受cpu指令并行优化的影响
????????????????
在Java里面,可以通过volatile关键字来保证一定的“有序性”(volatile关键字能禁止指令重排序,所以volatile能在一定程度上保证有序性)。另外可以通过synchronized和Lock来保证有序性,很显然,synchronized和Lock保证每个时刻是有一个线程执行同步代码,相当于是让线程顺序执行同步代码,自然就保证了有序性。
????????????????另外,Java内存模型具备一些先天的“有序性”,即不需要通过任何手段就能够得到保证的有序性,这个通常也称为 happens-before 原则。如果两个操作的执行次序无法从happens-before原则推导出来,那么它们就不能保证它们的有序性,虚拟机可以随意地对它们进行重排序。



可见性
? ? ?
? 先来看一个现象 main线程对run变量的修改对于t线程不可见 导致了t线程无法停止
? ? ? ? ? ? ? ? 主线程先运行 主线程运行之后 新建的线程才运行 新建的线程还没有进行while()循环呢
主线程就结束了 所以要让主线程sleep一下 不然run=false对while循环不起作用

import static java.lang.Thread.sleep;

public class VOASD {
    static boolean run = true;
    public static void main(String[] args) throws InterruptedException {
        new Thread(()->{
            while (run){

            }
        }).start();
        sleep(1);
        run = false;//线程t不会如预想的停下来
    }
}

分析:
????????
1.初始状态 t线程刚开始从主存读取了run的值 到工作内存

?????????2.因为t线程要频繁从主内存中读取run的值(while循环)? ?JIT编译器会将run的值缓存至自己工作内存中的 高速缓存中 减少对主存中run的访问 提高效率

? ? ? ? ?3.1秒之后 main线程修改了run的值 并同步至主存 而t是从自己工作内存中的高速缓存中读取这个变量的值 结果永远是旧值? ? ????解决办法:
????????volatile static boolean run = true;?
? ? ? ? ? ? ? ? 加了volatile关键字之后的变量就不能从缓存中读取了 必须从主内存中找最新值

? ? ? ? volatile(易变关键字)
? ? ? ? ? ? ? ? 它可以用来修饰成员变量和静态成员变量 可以避免线程从自己的工作缓存中查找变量的值 必须到主存中获取它的值 线程操作volatile变量都是直接操作主存
?


可见性VS原子性
? ? ?
? 前面的例子体现的实际就是可见性 它保证的是在多个线程之间 一个线程对volatile变量的修改对另一个线程可见 不能保证原子性 仅用在一个写线程 多个读线程的情况
上面的例子从字节码理解是这样的

? ? ? ? ?比如线程安全时 举的例子 卖票问题 或者 两个线程一个i++ 一个i-- 只能保证看到最新值 不能解决指令交错? ? ? ? ? ?volatile只能保证 getstatic读到的是最新的值

? ?????????synchronized语句既可以保证代码块的原子性 也同时保证代码块内变量的可见性 但缺点是
synchronized是属于重量级操作 性能相对更低
? ? ? ? ? ?? ? ?

有序性?
? ? ? ?
JVM会在不影响正确性的前提下 可以调整语句的执行顺序 思考下面一段代码
? ? ? ??
? ? ? ? 可以看到 至于是先执行i还是先执行j 对最终的结果不会产生影响 所以 上面代码真正执行
时 既可以是
????????
也可以是
????????????????
? ? ? ? 这种特性称之为[指令重排]? ?多线程下指令重排会影响正确性

指令重排的前提是 重排指令不能影响结果

Volatile关键字
?????????volatile 是java虚拟机提供的轻量级同步机制
? ? ? ? ? ? ?
特性:

????????可见性

????????不保证原子性

????????禁止指令重排

?volatile的底层原理是内存屏障:
? ? ?
? ·对volatile变量的写指令后会加入写屏障
????????·对volatile变量的读指令后会加入读屏障


如何保证可见性
? ? ? ?
写屏障保证在该屏障之前的 对共享变量的改动 都同步到主存当中

? ? ? ? 读屏障保证在该屏障之后 对共享变量的读取 加载的是主存中最新数据

?

如何保证有序性
? ? ? ?
写屏障会确保指令重排序时 不会将写屏障之前的代码排在写屏障之后

?????????

? ? ? ? ?读屏障会确保指令重排序时 不会将读屏障之后的代码排再读屏障之前

?

volatile不能解决指令交错(不能保证原子性)
? ? ? ? 写屏障仅仅是保证之后的读能读到最新的结果 但不能保证读跑到它前面去
? ? ? ? 而有序性的保证也只是保证了本线程内相关代码不被重排序

?synchronized可以同时解决有序 可见 原子性

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-04-14 23:36:51  更:2022-04-14 23:38:42 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 4:21:00-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码