文档章节

Java 复习 —— JMM基础

learn_more
 learn_more
发布于 2015/09/14 15:14
字数 1240
阅读 91
收藏 9

码上生花,ECharts 作品展示赛正式启动!>>>

基本内容

1、共享变量在线程间的可见性

2、synchronized实现可见性

3、volatile 实现可见性

1)指令重排序

2)as-if-serial

3)volatile 使用注意事项

4、volatile和synchronized的比较

1、可见性

一个线程对共享变量值的修改,能够及时地被其他线程看到。

共享变量:如果一个变量在多个线程的工作内存中都存在副本,那么这个变量就是这几个线程的共享变量。

Java内存模型(JMM):描述了Java程序中各种变量(共享变量)的访问规则,以及在JVM中将变量存储到内存和从内存中读取出变量这样的底层细节。

2、JMM 基本规则

1)所有的变量都存储在在主内存中。

2)每个线程都有自己独立的工作内存,里面保存该线程使用到的变量副本(主内存中该变量的一份拷贝)。

3)线程对共享变量的所有操作都必须在自己的工作内存中进行,不能直接从主内存中读写

4)不同线程之间无法直接访问其他线程工作内存中的变量,线程间变量值的传递需要通过主内存来完成。

3、共享变量实现可见性的原理

1)首先在自己线程Thread1里修改共享变量x=1

2)然后更新主内存的x=1

3)其次其他线程Thread2从主内存中读取x=1,更新自己线程的值,

这样连续性的操作,可以保证任何一个线程的独立内存中的共享变量都是最新的值!

4、Java层面实现可见性的方式

1)synchronized

2)volatile

3)concurrent 包

5、synchronized

1)线程解锁前,必须把共享变量的最新值刷新到主内存中

2)线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量时需要从主内存中重新读取最新的值。(注意:加锁与解锁需要同一把锁)

6、synchronized 修饰时,JVM操作的步骤

1)首先获得互斥锁

2)清空工作内存

3)从主内存拷贝变量的最新副本到工作内存

4)执行代码

5)将更改后的共享变量值刷新到主内存

6)释放互斥锁

7、重排序

代码书写的顺序与实际执行的顺序不同,指令重排序是编译器或处理器为了提高程序性能而做的优化!

1)编译器优化

2)指令优化

3)内存系统优化

最后的结果:有可能导致代码的执行的顺序与编写顺序不一致,但是可以提高CPU性能

8、as-if-serial

无论如何重排序,程序的运行结果都是保持一致的!

单线程中是不能会因为重排序带来内存可见性的问题。

多线程则会由于重排序带来共享变量不一致的问题。

9、导致共享变量在线程间不可见的原因

1)线程交叉执行。(原子性来保证)

2)重排序结合线程交叉执行。(原子性来保证)

3)共享变量未及时更新。(内存可见性来保证)

10、synchronized 修饰变量、修饰方法或代码块

1)拥有原子性

2)拥有内存可见性

3)重量级

所以他能够实现线程间执行操作的安全性!

11、volatile 修饰变量

1)不保证原子性

2)拥有可见性

3)轻量级

12、关于 i++

1)首先读取,从主内存中读取i的值更新到当前工作内存中

2)其次改变,对i进行加1

3)最后更新,从当前工作内存中的值刷新到主内存中去

所以,这不是一个原子操作,在这个操作过程中势必会导致线程间交互而导致值的混乱!解决方式就是保证 i++ 具有原子性

1)使用synchronized

2)使用Lock对象,concurrent 包中

Lock lock = new RentrantLock();

try{

    lock.lock();

    i++

}finally{

    lock.unlock();

}

13、volatile 使用场合

1)对变量的写入操作不依赖其当前值,比如Boolean值,但是 i++ 或 i=i+5

2)该变量没有包含在其他变量的不变式中,比如: low < high (这里我也不是很清楚)

注意:共享变量都必须是private

final 也实现了内存可见性,因为他的值是不可修改的!

14、结论

对一个共享变量不仅仅要关心他的写,还关心他的读,二者都要加锁;

volatile是轻量级的,能使用,尽量使用!


© 著作权归作者所有

learn_more
粉丝 93
博文 240
码字总数 210196
作品 0
深圳
程序员
私信 提问
加载中
请先登录后再评论。
【并发编程】Java并发编程传送门

本博客系列是学习并发编程过程中的记录总结。由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅。 并发编程系列博客传送门 背景知识 【并发编程】摩尔定律失效“...

osc_nbqoh20k
2019/12/02
12
0
Jenkins 多环境 CI/CD 架构设计

  ———— e n d ————   金三银四,师长为大家准备了三份面试宝典:   《java面试宝典5.0》   《350道Java面试题:整理自100+公司》   《资深java面试宝典-视频版》   分别...

java进阶架构师
03/13
0
0
JAVA基础入门(JDK、eclipse下载安装)

最近打算从基础复习下,去年这个时间开始学习的,感觉好多都忘记了(自己记忆不深刻,容易忘事) 都是自己理解,如果有错误欢迎指正! 09年Sun公司被Oracle公司收购 javaSE:基础核心,程序开...

osc_8i32hj13
2019/07/03
2
0
Java 理论与实践: 修复 Java 内存模型,第 2 部分 (VOLATILE, FINA...

活跃了将近三年的 JSR 133,近期发布了关于如何修复 Java 内存模型(Java Memory Model, JMM)的公开建议。在本系列文章的 第 1 部分,专栏作者 Brian Goetz 主要介绍最初的 JMM 中的几个严重...

刘小兵2014
2011/07/28
118
0
并发系列(二)----Java内存模型

一 简介 在并发编程中,两个线程(A、B)同时操作一个普通变量的时候会出现线程A在操作变量时线程B也将变量操作了,此时线程A是无法感知变量发生变化的,造成变量改变错误。更据以上例子我们...

osc_lqlcgocs
2018/07/07
6
0

没有更多内容

加载失败,请刷新页面

加载更多

Java 项目工程搭建 --创建子模块(Spring Initializr)

一下篇,常用 Java 项目工程搭建 --创建子模块(依赖父工程) 也不算常用,常用的是 ctrl+c、ctrl+v ,哈哈 Package要手动改下,生成的很丑 选能支持 Alibaba Cloud 的版本 不然会跑到根目录...

osc_qheq8wav
6分钟前
3
0
C++指针相关问题

C++指针相关问题 一、总结 一句话总结: a、数组名是这个数组的首地址:a[3][4]:a int(*)[4]、&a int(*)[3][4]、a[0] int*、a[0][0] int b、int ** 表示指向指针的指针:int m = 1; int *p...

osc_35ne77sz
7分钟前
5
0
好兄弟仅用3年,就做到了架构师的位置,真心羡慕!经验分享给你

昨天跟好兄弟聊天,得知了他最近晋升了架构师的消息,是真的羡慕。要知道,我这个兄弟仅用了三年的时间,就做到了架构师的位置,真的优秀! 懂得多门主流编程语言如C++、Java、python等,可以...

osc_vnopwmym
8分钟前
7
0
C 实战练习题目40

题目:将一个数组逆序输出。 程序分析:用第一个与最后一个交换。 实例: 1 #include<stdio.h> 2 #define N 10 3 int main() 4 { 5 int a[N]={0,1,2,3,4,5,6,7,8,9}; 6 int i,...

osc_o1iwxx3z
10分钟前
25
0
C 实战练习题目36 – 求100之内的素数

题目:求100之内的素数。 程序分析:质数(prime number)又称素数,有无限个。一个大于1的自然数,除了1和它本身外,不能被其他自然数整除。 实例: 1 #include<stdio.h> 2 #include<mat...

osc_t4xzns0d
10分钟前
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部