JVM笔记 – 高效并发(Java内存模型与线程)
本文由发表于3年前 | J2EE | 暂无评论 |  被围观 3,099 views+
1、概述2、硬件的效率与一致性3、Java内存模型3.1、主内存与工作内存3.2、内存间交互操作3.3、对于volatile型变量的特殊规则当一个变量定义为volitile之后,它将具备两种特性。第一是保证此变量对所有线程的可见性。使用volatile变量的第二个语义是禁止指令重排优化。3.4、对于long和double型变量的特殊规则3.5、原子性、可见性与有序性原子性可见性有序性3.6、先行发生原则4、Java与线程4.1、线程的实现使用内核线程实现使用用户线程实现使用用户线程加轻量级进程混合实现Java线程的实现4.2、Java线程调度4.3、状态转换以下方法会让线程陷入无限期的等待状态:5、本章小结
《深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)》笔记
1、概述
2、硬件的效率与一致性

基于告诉缓存的存储交互很好地解决了处理器与内存的速度矛盾,但是也为计算机系统带来了更高的复杂度,因为它引入了一个新的问题:缓存一致性。

处理器可能会对输入代码进行乱序执行优化,处理器会在计算之后将乱序执行的结果重组,保证该结果与顺序执行的结果是一致的。

3、Java内存模型

线程的工作内存中保存了被该线程使用到的变量的主内存副本拷贝,线程对变量的所有操作(读取、赋值等)都必须在工作内存中进行。

3.1、主内存与工作内存
3.2、内存间交互操作
3.3、对于volatile型变量的特殊规则
当一个变量定义为volitile之后,它将具备两种特性。
第一是保证此变量对所有线程的可见性。

volitile变量在各个线程中是一致的,并不能得出基于volitile变量的运算在并发下是安全的这个结论。

volatile变量的运算在并发下一样是不安全的。

当getstatic指令把变量的值取到操作栈顶时,volatile关键字保证了race的值在此时是正确的,但是在执行iconst_1、iadd这些指令的时候,其他线程可能已经把变量的值加大了。

由于volatile变量只能保证可见性,在不符合以下两条规则的运算场景中,我们仍然要通过加锁(使用synchronized或java.util.concurrent中的原子类)来保证原子性:

  • 运算结果并不依赖变量的当前值,或者能够确保只有单一的线程变量的值。
  • 变量不需要与其他的状态变量共同参与不变约束。
使用volatile变量的第二个语义是禁止指令重排优化。

普通的变量仅仅会保证在该方法的执行过程中所有依赖赋值结果的地方都能获取到正确的结果而不能保证变量赋值操作的顺序与程序代码中的执行顺序一致。

指令重排是并发编程中最容易让开发人员产生疑惑的地方,volitile关键字可以禁止指令重排序优化。

volatile变量读取操作的性能消耗与普通变量几乎没有什么差别,但是写操作则可能会慢一些,因为它需要再笨的代码中插入许多内存屏障指令来保证处理器不发生乱序执行。不过即便如此,大多数场景下volatile的总开销仍然要比锁第,我们在volatile与锁之中选择的唯一依据仅仅是volatile的语义能否满足使用场景的需求。

如一个变量的修改不依赖与原值,则这个时候可以使用volatile关键字实现先行发生关系。
3.4、对于long和double型变量的特殊规则

在实际开发中,目前各种平台下的商用虚拟机几乎都选择把64位数据的读写操作作为原子操作来对待,因此我们在编码时一般不需要把用到的long和double变量专门声明为volatile。

3.5、原子性、可见性与有序性
原子性

由Java内存模型来直接保证的原子性变量操作包括:read、load、assign、use、store和write。

可见性

Java内存模型是通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值这种依赖主内存作为传递媒介的方式来实现可见性的,无论是普通变量还是volatile变量都是如此,普通变量与volatile变量的区别是,volatile的特殊规则保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新。因此可以说volatile保证了多线程操作时变量的可见性,而普通变量则不能保证这一点。

除了volatile之外,Java还有两个关键字能实现可见性,即synchronized和final。

有序性

Java语言提供了volatile和synchronized两个关键字来保证线程之间操作的有序性,volatile关键字本身就包含了禁止指令重排序的语义,而synchronized则是由“一个变量在同一个时刻只允许一条线程对其进行lock操作”这条规则获得的,这条规则决定了持有同一个锁的两个同步块只能串行地进入。

大部分并发控制都能使用synchronized来完成。synchronized的“万能”也间接早就了它被程序员滥用的局面,越“万能”的并发控制,通常会伴随着越大的性能影响。

3.6、先行发生原则

依靠这个原则,我们可以通过几条规则一揽子地解决并发环境下两个操作之间是否可能存在冲突的所有问题。

下面是Java内存模型下一些“天然的”先行发生关系:

  • 程序次序规则
  • 管程锁定规则
  • volatile变量规则
  • 线程启动规则
  • 线程终止规则
  • 线程中断规则
  • 对象终结规则
  • 传递性
4、Java与线程
4.1、线程的实现

Thread类与大部分的Java API有显著的差别,它的所有关键方法都是声明为Native的。

实现线程主要有3种方式:使用内核线程实现、使用用户线程实现和使用用户线程加轻量级进程混合实现。

使用内核线程实现

由于是基于内核线程实现的,所以各种线程操作,如创建、析构及同步,都需要进行系统调用。而系统调用的

使用用户线程实现
使用用户线程加轻量级进程混合实现
Java线程的实现
4.2、Java线程调度

分为协同式线程调度和抢占式线程调度。Java使用的线程调度方式就是抢占式调度。

线程优先级并不是太靠谱,原因是Java的线程是通过映射到系统的原生线程上来实现的,所以线程调度最终还是取决于操作系统。

4.3、状态转换
以下方法会让线程陷入无限期的等待状态:
  • 没有设置Timeout参数的Object.wait()方法
  • 没有设置Timeout参数的Thread.join()方法
  • LockSupport.park()方法

以下方法会让线程进入限期等待状体:

  • Thread.sleep()
  • 设置了Timeout参数的Object.wait()方法
  • 设置了Timeout参数的Thread.join()方法
  • LockSupport.parkNanos()方法
  • LockSupport.parkUntil()方法
5、本章小结
除了文章中有特别说明,均为IT宅原创文章,转载请以链接形式注明出处。
本文链接:http://www.itzhai.com/jvm-note-efficient-concurrent-1.html
关键字: ,
arthinking Java技术交流群:280755654,入门群:428693174 more
分享到:
 
2015 3/1
如果您有更好的原创技术博文或者观点,欢迎投稿:admin@itzhai.com,或者关注订阅左侧浮动面板的微信号订阅IT宅itread)发送消息。
文章评论
    没有评论
给我留言

有人回复时邮件通知我
J2EE的相关文章
随机文章 本月热门 热评
1 Java源码分析 – ArrayList动态数组列表源码分析 2011/10/10
2 Struts2单选按钮标签s:radio的使用及其设置默认值 2011/9/10
3 Java Web笔记 – JSP的语法和相关指令语法原理分析 编译器指令 动作语法 声明指令 2011/11/9
4 碰撞球(连连看)游戏 连连看匹配算法分析与实现思路 2012/4/10
5 Java源码分析 – 策略模式在Java集合框架实现代码中的体现 2011/10/17
6 源代码阅读方法 jQuery源码解析 核心模块core.js 2013/1/14
友情推荐 更多
破博客 文官洗碗安天下,武将打怪定乾坤。多么美好的年代,思之令人泪落。
Mr.5's Life 白天是一名程序员,晚上就是个有抱负的探索者
行知-追寻技术之美 关注大数据,分布式系统
我爱编程 编程成长轨迹
Cynthia's Blog 学习笔记 知识总结 思考感悟
 
猜您喜欢
欢迎关注我的公众号 IT宅
关于IT宅 文章归档

IT宅中的文章除了标题注明转载或有特别说明的文章,均为IT宅的技术知识总结,学习笔记或随笔。如果喜欢,请使用文章下面提供的分享组件。转载请注明出处并加入文章的原链接。 感谢大家的支持。

联系我们:admin@itzhai.com

Theme by arthinking. Copyright © 2011-2015 IT宅.com 保留所有权利.