一、很多初学者分不清JMM和JVM的内存模型,本篇只是简要的谈一谈什么是JMM,并不深入探讨。

  示意图A:

  

  在多线程操纵共享资源时,并不是对资源本身进行的操作,而是将共享资源的副本复制了一份到自己的私有空间中,等使用完了再写回去覆盖原资源,我可能在瞎说,你先别信,举个例子来验证一下:

  


class Number{
int count = 0;
public void add(){
this.count = 1;
}
}
public class Demo2 {
public static void main(String[] args) {
Number number = new Number(); new Thread(() -> {
System.out.println(Thread.currentThread().getName()+"***come in");
try{
TimeUnit.SECONDS.sleep(5);
}catch (Exception e){
e.printStackTrace();
}
number.add();
System.out.println(Thread.currentThread().getName()+" newCount: " + number.count);
},"A").start();
new Thread(() -> {
System.out.println(Thread.currentThread().getName()+"***come in");
while (number.count == 0){
try{
Thread.sleep(1000);
System.out.println("wait...");
            //重新从主内存获取资源(number.count)
            //System.out.println(Thread.currentThread().getName() + " newCount: " + number.count);
                }catch (Exception e){
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+" newCount: " + number.count);
},"B").start();
}
}
 

  输出结果很奇怪:A线程将count设置为1结束后,B线程却不停的每秒钟输出一个wait... , 为什么A线程将count设置为1,B没有跳出while循环呢?因为B并不知道A已经将count值改变了,A线程用的count是之前从主内存拷贝而来的,而不是直接使用的主内存中的number的count。A也是先将主内存中的内容复制到自己的私有工作内存空间中,但是进行操作后便将数据写会到主内存中,但这些操作B线程并不知道,只有B线程重新获取资源才会知道主内存资源发生了改变,因此如何让B线程“知道”A线程已经将数据改变,是由现实需求的。

二、volatile关键字

class Number{
volatile int count = 0;
public void add(){
this.count = 1;
}
}

  给count变量加一个volatile关键字修饰,A线程修改count值后,即使B线程没有主动从主内存中获取最新资源,也会有一种“通知机制”告诉他你的值不是最新的了,你需要从主内存中获取最新的资源,两个线程是这样,多个线程也是这样。我们称这样的通知机制为“可见性”。

  可见性:1、修改volatile变量时会强制将修改后的值刷新到主内存中

      2、修改volatile变量后会导致其他线程工作内存中的对应变量值失效。因此,再读取该变量值的时候就需要重新从主内存中读取新值。

  

  上面的add()方法里面操作时原子性操作,如果如果把add()方法改成:

class Number{
volatile int count = 0;
public void add(){
this.count = count++;//count++不是原子性操作
}
}

  输出结果和没有加volatile是一样的,还是不停的输出wait... ,也就是说volatile适用于原子性操作,那如果对变量的操作不是原子性操作,怎么才能实现这种通信呢?使用锁!

class Number{
volatile int count = 0;
public synchronized void add(){
this.count = count++;
}
}
class Number{
Lock lock = new ReentrantLock();
volatile int count = 0;
public synchronized void add(){
lock.lock();
try{
this.count = count++;
}finally {
lock.unlock();
}
}
}

  通过加锁,也可以实现 “原子性”。我们来分析一下为什么为什么count++不是原子性操作,执行count++,一共分为三步,将内存中的count读到CPU寄存器,然后执行自增操作,最后写回内存。

简述JMM的更多相关文章

  1. 简述 OAuth 2.0 的运作流程

    本文将以用户使用 github 登录网站留言为例,简述 OAuth 2.0 的运作流程. 假如我有一个网站,你是我网站上的访客,看了文章想留言表示「朕已阅」,留言时发现有这个网站的帐号才能够留言,此时 ...

  2. JavaScript单线程和浏览器事件循环简述

    JavaScript单线程 在上篇博客<Promise的前世今生和妙用技巧>的开篇中,我们曾简述了JavaScript的单线程机制和浏览器的事件模型.应很多网友的回复,在这篇文章中将继续展 ...

  3. Design Patterns Simplified - Part 3 (Simple Factory)【设计模式简述--第三部分(简单工厂)】

    原文链接:http://www.c-sharpcorner.com/UploadFile/19b1bd/design-patterns-simplified-part3-factory/ Design ...

  4. 浅析java内存模型--JMM(Java Memory Model)

    在并发编程中,多个线程之间采取什么机制进行通信(信息交换),什么机制进行数据的同步? 在Java语言中,采用的是共享内存模型来实现多线程之间的信息交换和数据同步的. 线程之间通过共享程序公共的状态,通 ...

  5. JMM(java内存模型)

    What is a memory model, anyway? In multiprocessorsystems, processors generally have one or more laye ...

  6. Android网络定位服务定制简述

    Android 添加高德或百度网络定位服务 Android的网络定位服务以第三方的APK方式提供服务,由于在国内Android原生自带的com.google.android.gms服务几乎处于不可用状 ...

  7. 《Entity Framework 6 Recipes》翻译系列 (1) -----第一章 开始使用实体框架之历史和框架简述

    微软的Entity Framework 受到越来越多人的关注和使用,Entity Framework7.0版本也即将发行.虽然已经开源,可遗憾的是,国内没有关于它的书籍,更不用说好书了,可能是因为EF ...

  8. JMM和happens-before原则

    JMM: Java Memory Model(Java内存模型),围绕着在并发过程中如何处理可见性.原子性.有序性这三个特性而建立的模型. 可见性: JMM提供了volatile变量定义.final. ...

  9. 简述ASP.NET MVC原理

    1.为什么ASP.NET需要MVC? 因为随着网站的的数量级越来越大,原始的网站方式,这里指的是WebForm,在运行速度和维护性方面,以及代码量上面,越来越难以满足日益庞大的网站维护成本.代码的重构 ...

随机推荐

  1. .NetCore WebApi —— Swagger版本控制

    目录: .NetCore WebApi——Swagger简单配置 .NetCore WebApi——基于JWT的简单身份认证与授权(Swagger) .NetCore WebApi —— Swagge ...

  2. 富文编辑器和bs4简单实用

    目录 使用方法 官方网址 图片上传下载实例 菜单栏功能筛选 bs4 导入 提取标签内的文本内容 目录 使用方法 直接给输入框绑定事件即可,注意引入js方式有点不一样,多加编码方式 <script ...

  3. mpvue 星星打分组件

    上图: <template> <div class="container"> <div v-for="(star,index) in sta ...

  4. Arouter核心思路和源码详解

    前言 阅读本文之前,建议读者: 对Arouter的使用有一定的了解. 对Apt技术有所了解. Arouter是一款Alibaba出品的优秀的路由框架,本文不对其进行全面的分析,只对其最重要的功能进行源 ...

  5. C语言--最大公约数

    //辗转相除法 int main() { int a,b; int t; scanf("%d %d", &a,&b); ) { t = a%b; a = b; b ...

  6. Linux之常用命令I

    一.Linux简介 1)Minix(只为教学,开源的)-->Linux(以前者为模板,添加了一些软件) 2)Linux分为内核版本和发行版本 区别:Linux内核版本就是核心版本,不用最新版本, ...

  7. vue-electron 使用sqlite3数据库,执行npm run build 报错 .NET Framework 2.0 SDK,Microsoft Visual Studio 2005[C:\temp\wechat\node_modules\sqlite3\build\binding.sln]

    问题描述 vue-electron 使用sqlite3数据库,执行npm run build 报错如下: .NET Framework 2.0 SDK,Microsoft Visual Studio ...

  8. 设置Linux支持中文

    1.首先在command输入locale,可以看到Linux下默认的系统语言的是英文 2.vim ~/.bashrc打开这个文件,该文件夹相当于系统配置文件 3.打开后,将后三行命令输入到文档中,最后 ...

  9. 攻防世界(XCTF)逆向部分write up(一)

    晚上做几个简单的ctf逆向睡的更好 logmein elf文件 ida看看main函数伪代码 void __fastcall __noreturn main(__int64 a1, char **a2 ...

  10. Figures Inscribed in Curves (曲线上的图形)

    Figures Inscribed in Curves\text{Figures Inscribed in Curves}Figures Inscribed in Curves A short tou ...