简述JMM
一、很多初学者分不清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的更多相关文章
- 简述 OAuth 2.0 的运作流程
本文将以用户使用 github 登录网站留言为例,简述 OAuth 2.0 的运作流程. 假如我有一个网站,你是我网站上的访客,看了文章想留言表示「朕已阅」,留言时发现有这个网站的帐号才能够留言,此时 ...
- JavaScript单线程和浏览器事件循环简述
JavaScript单线程 在上篇博客<Promise的前世今生和妙用技巧>的开篇中,我们曾简述了JavaScript的单线程机制和浏览器的事件模型.应很多网友的回复,在这篇文章中将继续展 ...
- Design Patterns Simplified - Part 3 (Simple Factory)【设计模式简述--第三部分(简单工厂)】
原文链接:http://www.c-sharpcorner.com/UploadFile/19b1bd/design-patterns-simplified-part3-factory/ Design ...
- 浅析java内存模型--JMM(Java Memory Model)
在并发编程中,多个线程之间采取什么机制进行通信(信息交换),什么机制进行数据的同步? 在Java语言中,采用的是共享内存模型来实现多线程之间的信息交换和数据同步的. 线程之间通过共享程序公共的状态,通 ...
- JMM(java内存模型)
What is a memory model, anyway? In multiprocessorsystems, processors generally have one or more laye ...
- Android网络定位服务定制简述
Android 添加高德或百度网络定位服务 Android的网络定位服务以第三方的APK方式提供服务,由于在国内Android原生自带的com.google.android.gms服务几乎处于不可用状 ...
- 《Entity Framework 6 Recipes》翻译系列 (1) -----第一章 开始使用实体框架之历史和框架简述
微软的Entity Framework 受到越来越多人的关注和使用,Entity Framework7.0版本也即将发行.虽然已经开源,可遗憾的是,国内没有关于它的书籍,更不用说好书了,可能是因为EF ...
- JMM和happens-before原则
JMM: Java Memory Model(Java内存模型),围绕着在并发过程中如何处理可见性.原子性.有序性这三个特性而建立的模型. 可见性: JMM提供了volatile变量定义.final. ...
- 简述ASP.NET MVC原理
1.为什么ASP.NET需要MVC? 因为随着网站的的数量级越来越大,原始的网站方式,这里指的是WebForm,在运行速度和维护性方面,以及代码量上面,越来越难以满足日益庞大的网站维护成本.代码的重构 ...
随机推荐
- ssrf漏洞学习(PHP)
自己最近原本是想深入的学习一下关于xss.csrf的东西的,可是感觉这些东西需要有很好的js的基础来进行学习..还有感觉自己感觉也差不多该要学习内网渗透了..正好ssrf在内网这一块也是比较有用的.于 ...
- Python 爬虫从入门到进阶之路(十)
之前的文章我们介绍了一下 Python 中正则表达式和 re 模块来做一个案例,爬取<糗事百科>的糗事并存储到本地.本章我们来看一下另一种爬取数据的方式 XPath. 我们在前面爬取< ...
- python编程基础之十三
列表的通用操作: list1 = [43, 65, 76, 6] list2 = [45, 77, 90, 11, 2, 4, 66] print(list1+ list2) # 列表组合 prin ...
- SQL SERVER数据库内,需要序列号进行排序时,排序方法
举例如下: SELECT ROW_NUMBER()OVER(ORDER BY (SELECT 0)) AS ROWNUM,* FROM YXHIS2018..TBMZGHMX201801 --不排序S ...
- Idea项目注释规范设置
Idea项目注释规范设置文档 1.类注释: /** *@ClassName: ${NAME} *@Description: TODO *@Author: guohui *@Da ...
- Ubuntu16.04 安装apache+mysql+php(LAMP)
记录下ubuntu环境下安装apache+mysql+php(LAMP)环境. 0x01安装apache sudo apt-get update sudo apt-get install apache ...
- Hadoop和YARN :map+shuffle+reduce走读
今天做了一个hadoop分享,总结下来,包括mapreduce,及shuffle深度讲解,还有YARN框架的详细说明等. v\:* {behavior:url(#default#VML);} o\:* ...
- SpringBootSecurity学习(26)前后端分离版之github单点登录
单点登录(SSO) 关于oauth2.0,最后我们再来学习一下单点登录.前面介绍过单点登录的定义,单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一. ...
- 生产环境中利用软链接避免"rm -rf /"的方法
1.将系统中的rm二进制文件重命名为rm_real:2.编写脚本rm_shell,rm_shell中主要包含以下内容: 2.1)路径转换模块,用于将rm_shell参数中的路径转换为绝对路径 ...
- LWIP移植文件介绍
在介绍文件之前首先介绍一下DMA描述符 stm32以太网模块接收/发送FIFO和内存之间的以太网传输是通过以太网DMA使用DMA描述符完成的,一共有两个描述符列表:一个用于接收,一个用于发送, 两个列 ...