Java线程模型
来源:互联网 发布:数据共享保密管理 编辑:程序博客网 时间:2024/05/16 05:16
Java 多线程并发程序出问题非常比较难发现。测试人员在低并发的情况下,无法测试到这种情况,一到高并发上线的时候,不定时的出现问题。所以在写这些高并发应用程序应该各位小心,同时也必须深入了解Java的内存模型JSR133。本文部分参考了http://ifeve.com/memory-model/
重排序导致的问题
如下demo,假设有两个线程,线程A调用writer操作,线程B调用reader操作。那么当线程B读y=2的情况下,是否意味着r2肯定是1呢?答案是否定的。原因是A线程的writer操作可能进行过重排序,y的赋值在x的赋值前面。这也导致了r1是2,而r2可能还是0。
应用程序可能会有如下几种重排序:
- 编译器重排序。 编译器为了优化,遍出来的指令为经过优化,和程序员的初始代码不同。
- 处理器优化重排序。处理器在不影响本线程 最终结果的情况下,优化指令的执行顺序。
- 内存优化重排序。
class Reordering {int x = 0, y = 0;public void writer() {x = 1;y = 2;}public void reader(){int r1 = y;int r2 = x;}}
处理器寄存器缓存导致的问题
为了提高执行速度,变量会在处理器中有相应的缓存,并不会立即刷入主存。同样为上节的代码,线程A更新了X的值,可能只会更新了处理线程A的处理器的寄存器,而并不会直接刷主存。 线程B从主存中读取x的值可能还是最初的老的值。
同理,处理线程B的处理器可能缓存了X的值,并没有读取最新主存中的值。
Happens-Before 原则
基于上面的问题JAVA内存模型JSR133引入了Happens-Before原则,来控制这些并发状态下的线程可见性问题。
- 顺序原则:一个线程中的操作,happens-before于该线程中的任意后续动作
- 锁原则:解锁之前的操作happens-before,后续获得该锁的操作
- volatile原则: volatile的写操作happens-before 后续的读操作
- 传递性原则: A Happens-before B,B happens-before C,则A happens-before
Volatile变量
volatile变量会避免处理器做任何的缓存优化,写的时候强行刷新主存内容。读的时候强行让本地缓存失效,去读主存内容。
这就保证了任何一个线程读的都是更新过的内容,内容也会被写线程及时更新。
Final变量
JSR133对final变量的规定是:- 构造函数中的final成员变量的写入,和这个构造完毕的对象赋值给引用,这两个不会被重排序。即final的成员变量写入,肯定保证在此对象被其他人引用之前写入完毕。
- 初次读一个包含final成员变量的引用,于初次读这个final成员变量不可重新被排序。
- 构造函数中final指针指向的成员变量,也会先赋值完毕,才可以被引用。
Synchronize 锁
锁是广大程序员最熟悉的机制。利用锁可以很好避免优化等造成的不同步问题。
0 0
- java线程模型 线程池
- java线程模型
- Java 线程模型
- java线程模型
- java 的线程模型
- Java线程模型缺陷
- Java线程模型总结
- Java线程模型
- java线程 状态模型
- 7.2 Java线程模型
- Java线程模型
- Java的线程模型
- Java的线程模型
- java线程内存模型
- 【多线程】Java线程模型
- java线程模型
- JAVA线程模型
- java线程模型
- 1012. 数字分类
- Spring--Spring AOP 实现原理与 CGLIB 应用
- Button按钮的几种点击事件的写法
- OC 笔记 20160330
- UIAlertView的使用
- Java线程模型
- AS3 event stopImmediatePropagation() stopPropagation()用法以及区别
- Android Handler 异步消息处理机制的妙用 创建强大的图片加载类
- 日常开发——Android多线程下载
- struts2自定义全局和局部类型转换器
- 返回数据给上一个活动(intent)
- Java堆、栈和常量池以及相关String的详细讲解(经典中的经典)
- 算法 - 判断两个二叉树是否相同
- 写写