Java内存可见性
如果一个线程对共享变量的修改,能够被其它线程看到,那么就能说明共享变量在线程之间是可见的。如果一个变量在多个线程的工作内存中都存在副本,那么这个变量就是这几个线程的共享变量。Java内存模型(Java Memory Model,JMM)描述了Java程序中各种变量(线程共享变量)的访问规则,以及在JVM中将变量存储到内存和从内存中读取出变量这样的底层细节。所有的变量都储存在主内存中。每个线程都有自己独立的工作内存,里面保存了该线程使用到的变量的副本(主内存中该变量的一份拷贝),如下图所示。

为什么会出现共享变量可见性的问题,这是因为线程对共享变量的所有操作都必须在自己的工作内存中进行,不能从主内存中读写;而且不同线程之间无法直接访问其它线程工作内存中的变量,线程间变量值的传递需要通过主内存来完成。线程1对共享变量的修改要想被线程2及时看到,必须要经过如下两个步骤:
1. 把工作内存1中更新过的共享变量刷新到主内存中;
2. 把内存中最新的共享变量的值更新到工作内存2中
Java语言层面支持的可见性实现方式有两种:
1. synchronized
2. volatile
synchronized不仅能通过互斥锁来实现同步,而且还能够实现可见性。Java内存模型关于Synchronized有两条规定:
* 线程释放锁之前,JMM会将工作内存中的共享变量刷新到主内存中;
* 线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量时需要从主内存中重新读取最新的值
线程执行互斥代码的过程:
1. 获取监视器锁
2. 清空工作内存
3. 从主内存中拷贝变量的最新副本到工作内存
4. 执行代码
5. 将更改后的共享变量的值刷新到主内存
6. 释放监视器锁
如果某个任务处于一个对标记为synchronized的方法的调用中,那么在这个线程从该方法返回之前,其它所有要调用类中任何标记为synchronized方法的线程都会被阻塞。
volatile通过加入内存屏障和禁止指令重排序优化来实现的:
* 对volatile变量执行写操作时,会在写操作后加入一条store屏障指令,这样就会把读写时的数据缓存加载到主内存中;
* 对volatile变量执行读操作时,会在读操作前加入一条load屏障指令,这样就会从主内存中加载变量;
所以说,volatile变量在每次被线程访问时,都强迫从主内存中重读该变量的值,而当该变量发生变化时,就会强迫线程将最新的值刷新到主内存,这样任何时刻,不同的线程总能看到该变量的最新值。
线程写volatile变量的过程:
1. 改变线程工作内存中volatile变量副本的值;
2. 将改变后的副本的值从工作内存刷新到主内存中
线程读volatile变量的过程:
1. 从主内存中读取volatile变量的最新值到线程的工作内存中;
2. 从工作内存中读取volatile变量的副本
Java内存可见性的更多相关文章
- 一个Java内存可见性问题的分析
如果熟悉Java并发编程的话,应该知道在多线程共享变量的情况下,存在“内存可见性问题”: 在一个线程中对某个变量进行赋值,然后在另外一个线程中读取该变量的值,读取到的可能仍然是以前的值: 这里并非说的 ...
- 从一个小例子引发的Java内存可见性的简单思考和猜想以及DCL单例模式中的volatile的核心作用
环境 OS Win10 CPU 4核8线程 IDE IntelliJ IDEA 2019.3 JDK 1.8 -server模式 场景 最初的代码 一个线程A根据flag的值执行死循环,另一个线程B只 ...
- Java内存可见性volatile
概述 JMM规范指出,每一个线程都有自己的工作内存(working memory),当变量的值发生变化时,先更新自己的工作内存,然后再拷贝到主存(main memory),这样其他线程就能读取到更新后 ...
- java 内存可见性
java线程 -> 线程工作内存 -> 主物理内存 线程工作内存的原理是栈内是连续的小空间,寻址速度比堆快得多,将变量拷贝到栈内生成副本再操作 什么是重排序 代码指令可能并不是严格按照代码 ...
- 从原子类和Unsafe来理解Java内存模型,AtomicInteger的incrementAndGet方法源码介绍,valueOffset偏移量的理解
众所周知,i++分为三步: 1. 读取i的值 2. 计算i+1 3. 将计算出i+1赋给i 可以使用锁来保持操作的原子性和变量可见性,用volatile保持值的可见性和操作顺序性: 从一个小例子引发的 ...
- 1 Java线程的内存可见性
Java内存的可见性 可见性: 一个线程对共享变量的修改,能够及时被其它线程看到 共享变量: 如果一个变量在多个线程的工作内存中都存在副本,那么这个变量就是这几个线程的共享变量 Java内存模型(JM ...
- 细说Java多线程之内存可见性
编程这些实践的知识技能,每一次学习使用可能都会有新的认识 一.细说Java多线程之内存可见性(数据挣用) 1.共享变量在线程间的可见性 共享变量:如果一个 ...
- Java内存模型——可见性
/** * 可见性问题 * @author Snway * */public class Visibility { private static boolean stop; ...
- Java内存模型JMM与可见性
Java内存模型JMM与可见性 标签(空格分隔): java 1 何为JMM JMM:通俗地讲,就是描述Java中各种变量(线程共享变量)的访问规则,以及在JVM中将变量存储到内存和从内存中读取变量这 ...
随机推荐
- 利用excel模板,将数据填充到excel中
package com.excel;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundExce ...
- IDEA创建Spring+SpringMVC+MyBatis(SSM)极简入门(上)
1. 创建项目 2. 添加Controller 3. pom+ properties+swager 4. 添加Mysql+ Mybatis 5. 调用Mybatis生成Mapper 1.创建 ...
- 【立体几何】Journey to Jupiter Gym - 101991J 立体几何模板
https://cn.vjudge.net/problem/Gym-101991J 题目很长,其实就是给你一个正三角形,并且告诉你它的中点在Z轴上以及法向量,边长和顶点A的坐标(自由度已定),让你求A ...
- day18:正则表达式和re模块
1,复习递归:返回值,不要只看到return就认为已经返回了,要看返回操作是在递归的第几层发生的,然后返回给了谁,如果不是返回给最外层函数,调用者就接收不到,需要再分析,看如何把结果返回回来,超过最大 ...
- python逻辑运算符规则
逻辑运算符:or and not 优先级:()>not>and>or 举例子: Print(2>1 and 1<4 or 2<3 and 9>6 or 2&l ...
- Django中一个项目使用多个数据库
在django项目中, 一个工程中存在多个APP应用很常见. 有时候希望不同的APP连接不同的数据库,这个时候需要建立多个数据库连接. 参考:http://blog.csdn.net/songfree ...
- linux 进程间通信——内存共享映射mmap和munmap
IPC三种通信机制是指:信号量.共享内存.消息队列, 信号量:通过操作系统中的PV操作来实现: 共享内存:申请一块内存,进程A往共享内存中写,其他的进程就可以通过读出共享内存中的内容来获取进程A所 ...
- python中Hadamard product和matrix product的区分
先简单说一下Hadamard product: (参照维基百科:https://en.wikipedia.org/wiki/Hadamard_product_(matrices)) 而matrix ...
- 如果merge分支出现问题,使用git方式查看日志
Administrator@IT-20161115IKEG MINGW32 ~$ cd e: Administrator@IT-20161115IKEG MINGW32 /e$ ls$RECYCLE. ...
- 利用spring实现服务启动就自动执行某些操作的2种方式
第一种方式,用bean的init-method属性 <bean class="com.emax.paycenter.log.LogBridge" init-method=&q ...