- 浏览: 1777319 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
奔跑的小牛:
例子都打不开
如何使用JVisualVM进行性能分析 -
蜗牛coder:
好东西[color=blue][/color]
Lucene学习:全文检索的基本原理 -
lovesunweina:
不在haoop中是在linux系统中,映射IP的时候,不能使用 ...
java.io.IOException: Incomplete HDFS URI, no host -
evening_xxxy:
挺好的, 谢谢分享
如何利用 JConsole观察分析Java程序的运行,进行排错调优 -
di1984HIT:
学习了~~~
ant使用ssh和linux交互 如:上传文件
好读书求甚解,共享展示,摘自:http://kenwu.me/explain-java-memory-model-in-detail
内存模型 (memory model)
内存模型描述的是程序中各变量(实例域、静态域和数组元素)之间的关系,以及在实际计算机系统中将变量存储到内存和从内存取出变量这样的低层细节.
不同平台间的处理器架构将直接影响内存模型的结构.
在C或C++中, 可以利用不同操作平台下的内存模型来编写并发程序. 但是, 这带给开发人员的是, 更高的学习成本.
相比之下, java利用了自身虚拟机的优势, 使内存模型不束缚于具体的处理器架构, 真正实现了跨平台.
(针对hotspot jvm, jrockit等不同的jvm, 内存模型也会不相同)
内存模型的特征:
a, Visibility 可视性 (多核,多线程间数据的共享)
b, Ordering 有序性 (对内存进行的操作应该是有序的)
java 内存模型 ( java memory model )
根据Java Language Specification中的说明, jvm系统中存在一个主内存(Main Memory或Java Heap Memory),Java中所有变量都储存在主存中,对于所有线程都是共享的。
每条线程都有自己的工作内存(Working Memory),工作内存中保存的是主存中某些变量的拷贝,线程对所有变量的操作都是在工作内存中进行,线程之间无法相互直接访问,变量传递均需要通过主存完成。
其中, 工作内存里的变量, 在多核处理器下, 将大部分储存于处理器高速缓存中, 高速缓存在不经过内存时, 也是不可见的.
jmm怎么体现 可视性(Visibility) ?
在jmm中, 通过并发线程修改变量值, 必须将线程变量同步回主存后, 其他线程才能访问到.
jmm怎么体现 有序性(Ordering) ?
通过java提供的同步机制或volatile关键字, 来保证内存的访问顺序.
缓存一致性(cache coherency)
什么是缓存一致性?
它是一种管理多处理器系统的高速缓存区结构,其可以保证数据在高速缓存区到内存的传输中不会丢失或重复。(来自wikipedia)
举例理解:
假如有一个处理器有一个更新了的变量值位于其缓存中,但还没有被写入主内存,这样别的处理器就可能会看不到这个更新的值.
解决缓存一致性的方法?
a, 顺序一致性模型:
要求某处理器对所改变的变量值立即进行传播, 并确保该值被所有处理器接受后, 才能继续执行其他指令.
b, 释放一致性模型: (类似jmm cache coherency)
允许处理器将改变的变量值延迟到释放锁时才进行传播.
jmm缓存一致性模型 – “happens-before ordering(先行发生排序)”
一般情况下的示例程序:
x = 0;
y = 0;
i = 0;
j = 0;
// thread A
y = 1;
x = 1;
// thread B
i = x;
j = y;
在如上程序中, 如果线程A,B在无保障情况下运行, 那么i,j各会是什么值呢?
答案是, 不确定. (00,01,10,11都有可能出现)
这里没有使用java同步机制, 所以 jmm 有序性和可视性 都无法得到保障.
happens-before ordering( 先行发生排序)
如何避免这种情况?
排序原则已经做到:
a, 在程序顺序中, 线程中的每一个操作, 发生在当前操作后面将要出现的每一个操作之前.
b, 对象监视器的解锁发生在等待获取对象锁的线程之前.
c, 对volitile关键字修饰的变量写入操作, 发生在对该变量的读取之前.
d, 对一个线程的 Thread.start() 调用 发生在启动的线程中的所有操作之前.
e, 线程中的所有操作 发生在从这个线程的 Thread.join()成功返回的所有其他线程之前.
为了实现 happends-before ordering原则, java及jdk提供的工具:
a, synchronized关键字
b, volatile关键字
c, final变量
d, java.util.concurrent.locks包(since jdk 1.5)
e, java.util.concurrent.atmoic包(since jdk 1.5)
…
使用了happens-before ordering的例子:
(1) 获取对象监视器的锁(lock)
(2) 清空工作内存数据, 从主存复制变量到当前工作内存, 即同步数据 (read and load)
(3) 执行代码,改变共享变量值 (use and assign)
(4) 将工作内存数据刷回主存 (store and write)
(5) 释放对象监视器的锁 (unlock)
注意: 其中4,5两步是同时进行的.
这边最核心的就是第二步, 他同步了主内存,即前一个线程对变量改动的结果,可以被当前线程获知!(利用了happens-before ordering原则)
对比之前的例子
如果多个线程同时执行一段未经锁保护的代码段,很有可能某条线程已经改动了变量的值,但是其他线程却无法看到这个改动,依然在旧的变量值上进行运算,最终导致不可预料的运算结果。
经典j2ee设计模式Double-Checked Locking失效问题
双重检查锁定失效问题,一直是JMM无法避免的缺陷之一.了解DCL失效问题, 可以帮助我们深入JMM运行原理.
要展示DCL失效问题, 首先要理解一个重要概念- 延迟加载(lazy loading).
非单例的单线程延迟加载示例:
class Foo { private Resource res = null; public Resource getResource() { // 普通的延迟加载 if (res == null) res = new Resource(); return res; } }
非单例的 多线程延迟加载示例:
Class Foo { Private Resource res = null; Public synchronized Resource getResource() { // 获取实例操作使用同步方式, 性能不高 If (res == null) res = new Resource(); return res; } }
非单例的 DCL多线程延迟加载示例:
Class Foo { Private Resource res = null; Public Resource getResource() { If (res == null) { //只有在第一次初始化时,才使用同步方式. synchronized(this) { if(res == null) { res = new Resource(); } } } return res; } }
Double-Checked Locking看起来是非常完美的。但是很遗憾,根据Java的语言规范,上面的代码是不可靠的。
出现上述问题, 最重要的2个原因如下:
1, 编译器优化了程序指令, 以加快cpu处理速度.
2, 多核cpu动态调整指令顺序, 以加快并行运算能力.
问题出现的顺序:
1, 线程A, 发现对象未实例化, 准备开始实例化
2, 由于编译器优化了程序指令, 允许对象在构造函数未调用完前, 将 共享变量的引用指向 部分构造的对象, 虽然对象未完全实例化, 但已经不为null了.
3, 线程B, 发现部分构造的对象已不是null, 则直接返回了该对象.
不过, 一些著名的开源框架, 包括jive,lenya等也都在使用DCL模式, 且未见一些极端异常.
说明, DCL失效问题的出现率还是比较低的.
接下来就是性能与稳定之间的选择了?
DCL的替代 Initialize-On-Demand :
public class Foo { // 似有静态内部类, 只有当有引用时, 该类才会被装载 private static class LazyFoo { public static Foo foo = new Foo(); } public static Foo getInstance() { return LazyFoo.foo; } }
维基百科的DCL解释:
http://en.wikipedia.org/wiki/Double-checked_locking
DCL的完美解决方案:
http://www.theserverside.com/patterns/thread.tss?thread_id=39606
总结:
多线程编程, 针对有写操作的变量, 必须 保证其所有引用点与主存中数据一致(考虑采用同步或volatile) .
发表评论
-
如何使用JVisualVM进行性能分析
2011-09-25 22:32 84850地址:https://visualvm.dev.java.ne ... -
JDK5中的concurrent包、线程池
2011-02-19 23:43 5018concurrent并发包里面几个 ... -
如何利用 JConsole观察分析Java程序的运行,进行排错调优
2010-11-12 18:38 187034一、JConsole是什么 从Java 5开始 引入 ... -
gentoo下 JAVA生成图片的问题 以及JFreeChart的图片问题
2010-11-05 17:21 6817=============================== ... -
JAVA NIO 详解Buffer类
2010-10-19 11:21 16525讲得很好,转载一下:http://www.java1995 ... -
简单的记录下 jconsole 查看远程机器的JAVA程序运行状况
2010-09-07 14:31 1760简单实用 远端: java \ ... -
项目管理 进度表
2010-06-27 14:43 3967项目管理中很重要的一部分 进度管理,进度管理又牵扯到进度表 ... -
JAVA基础 对象克隆 实现java.lang.Cloneable接口
2010-04-23 13:46 6047先来看看JDK的解释: ... -
深入浅出Java 类加载器
2010-03-05 11:42 4456简介: 类加载 ... -
Jave EE 6特性:依赖注入、Bean验证和EJB增强
2009-12-18 16:19 2046Java EE 的最新版本提供 ... -
JVM优化之调整大内存分页(LargePage)
2009-11-26 12:50 4187http://kenwu.me/tune-large-page ... -
JVM调优总结(一)一些概念
2009-11-24 14:43 1443原文地址:http://pengjiahe ... -
CentOS 5.2下配置Java和TOMCAT环境
2009-10-17 14:29 3731安装JDK: 1、下载解压(tar zxvf jdk.. ... -
web项目定时执行任务
2009-08-27 18:19 4288xml文件内容-监听器 < ... -
JAVA多线程的控制JAVA 5.0
2009-08-20 13:38 19960在Java 5.0之前启动一个任务是通过调用Thre ... -
JDK自带VM分析工具jps,jstat,jmap,jconsole
2009-08-09 10:24 35188一、概述 SUN ... -
log4j入门与提高-实例讲解
2009-08-04 09:47 6847官方网站:http://logging.apache.org/ ... -
获取Servlet运行环境信息-Servlet自身信息、Servlet服务器端信息和Servlet客户端信息
2009-07-08 15:01 7179在Servlet中可以很方便的获取各种运行环境信息,这些信 ... -
使用Perf4J进行性能分析和监控
2009-06-19 10:28 3508作者 Alex Devine 译者 崔 ... -
JAVA版PCX图象的RLE算法压缩与解压缩
2009-05-26 17:09 5928丰富JE的博客,把上大学时候的一个算法,搬过来,大概是2007 ...
相关推荐
Java内存模型详解,JVM结构..
Java内存模型详解JMM.docx
NULL 博文链接:https://kqy7758.iteye.com/blog/1025552
Java开发
首先希望大家喜欢我制作的文档,如果文档中有什么误解的地方,望告诉一下,5分是也不多,是系统默认的,那么就5分咯,java多线程详解,线程池原理,8种锁,java内存模型......
Android 内存 OOM 优化和治理,Android 内存泄漏原因详解与应对措施,Android 中的 Bitmap 使用详解,Android 中的 Bitmap 内存治理和优化详解,Android 内存分析命令详解,Java内存模型。Android 内存 OOM 优化和...
主要介绍了Java内存模型JMM详解,涉及volatile和监视器锁,final字段,内存屏障等相关内容,具有一定参考价值,需要的朋友可以了解下。
主要介绍了Java内存模型知识详解,文中通过对内存访问时的交互关系图解介绍的十分详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
本文分析了Java中堆内存与栈内存分配的异同
1.前言最近在研究JVM内存模型和Java基础知识。主要讲的是线程共享变量与线程私有变量以及如何写出线程安全的代码。这里列出一条规则,“类中的成员变量,也叫实例
java性能优化诊断与优化 基于 1:堆、堆栈及Java内存模型2:内存泄漏及垃圾回收算法3:Java启动参数设置 这三个方面进行讲述,详细分析了网站的性能优化方法。
主要介绍了Java内存模型与JVM运行时数据区的区别详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
本文主要介绍Java高并发内存模型和线程安全的资料,这里整理详细的资料及1.原子性 2.有序性 3.可见性 4.Happen-Before 5.线程安全的概念,有需要的小伙伴可以参考下
JVM(Java虚拟机)详解(JVM 内存模型、堆、GC、直接内存、性能调优)
深入详解JVM内存模型与JVM参数详细配置.pdf
深入详解JVM内存模型与JVM参数详细配置,感兴趣的小伙伴们可以一块学习下。
Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干不同的数据区域,这些区域都有各自的用途以及创建和销毁的时间。Java虚拟机所管理的内存将会包括以下几个运行时数据区域,如下图所示: ...
Java.Bug模式详解 第1章 混乱环境下的灵活方法 1.1 软件设计、实现和维护的趋势 1.1.1 对于稳定、安全 系统的需求增加 1.1.2 传统软件工程技 术的局限性 1.1.3 开放源代码的软 件项目的可利用性 1.1.4 对于...