JAVA并发编程学习笔记------对象的可见性及发布逸出
一、非原子的64位操作:
当线程在没有同步的情况下读取变量时,可能会得到一个失效值,但至少这个值是由之前某个线程设置的值,而不是一个随机值,这种安全性保证被称为最低安全性。最低安全性适用于绝大多数变量,但存在一个例外:非volatile类型的64位数值变量(double,long),Java内存模型要求,变量的读取和写入操作都必须是原子操作,但对于非volatile型的long,double变量,JVM允许将64位的读操作或写操作分解为两个32位的操作,当读取一个非volatile类型的long变量时,如果对该变量的读操作和写操作在不同的线程中执行,那么很可能会读取到某个值的高32位和另一个值的低32位。
因此,即使不考虑失效数据问题,在多线程中使用共享且可变的long,double等类型的变量也是不安全的,除非用关键字volatile来声明它们,或者用锁保护起来。
二、volatile变量
当把变量声明为volatile类型后,编译器与运行时都会注意到这个变量时共享的,因此不会将该变量上的操作与其他内存操作一起重排序。volatile变量不会被缓存在寄存器或者对其他处理器不可见的地方,因此在读取volatile类型的变量时总会返回最新写入的值。
volatile局限在于:它通常用于某个操作完成、发生中断或者状态的标志,其语义不足以确保递增操作的原子性,除非你能确保只有一个线程对变量执行写操作。
当且仅当满足以下条件时,才应该使用volatile变量:
1)对变量的写入操作不依赖变量的当前值,或者能确保只有单个线程更新变量的值;
2)该变量不会与其他状态变量一起纳入不变性条件中;
3)在访问变量时不需要加锁。
加锁机制既可以确保可见性又可以确保原子性,而volatile变量只能确保可见性。
三、对象的发布逸出
如下示例代码:
public class ThisEscape {
public ThisEscape(EventSource source) {
source.registerListener{
new EventListener()(){
public void onEvent(Event e){
doSomething(e);
}
}
}
}
}
这个类不是安全的,因为当ThisEscape发布EventListener时,也隐含的发布了ThisEscape实例本身,因为这个内部类的实例中包含了对ThisEscape实例的隐含应用,因此,当从对象的构造函数中发布对象时,只是发布了一个尚未构造完成的对象。即使发布对象的语句位于构造函数的最后一行也是如此。在构造函数中创建线程并没有错误,但最好不要立即启动它,而是通过一个start或initialize方法来启动,例如,可通过如下工厂方法来防止this引用在构造过程中逸出:
public class SafeListener {
private static final EventListener listener;
public SafeListener() {
listener = new EventListener() {
public void onEvent(Event e){
doSomeThing(e);
}
}
}
public static SafeListener newInstance(EventSource source){
SafeListener safe = new SafeListener();
source.registerListener(safe.listener);
return safe;
}
}
JAVA并发编程学习笔记------对象的可见性及发布逸出的更多相关文章
- Java并发编程学习笔记
Java编程思想,并发编程学习笔记. 一.基本的线程机制 1.定义任务:Runnable接口 线程可以驱动任务,因此需要一种描述任务的方式,这可以由Runnable接口来提供.要想定义任务,只需实现R ...
- Java并发编程学习笔记(二)——对象的共享
主要概念:可见性.重排序.失效数据.最低安全性.发布.逸出.线程封闭(Ad-hoc.栈封闭.ThreadLocal类).不变性.Final域.事实不可变对象. 1.在没有同步的情况下,编译器.处理器以 ...
- Java并发编程学习笔记 深入理解volatile关键字的作用
引言:以前只是看过介绍volatile的文章,对其的理解也只是停留在理论的层面上,由于最近在项目当中用到了关于并发方面的技术,所以下定决心深入研究一下java并发方面的知识.网上关于volatile的 ...
- Java 并发编程学习笔记 理解CLH队列锁算法
CLH算法实现 CLH队列中的结点QNode中含有一个locked字段,该字段若为true表示该线程需要获取锁,且不释放锁,为false表示线程释放了锁.结点之间是通过隐形的链表相连,之所以叫隐形的链 ...
- Java并发编程学习笔记(三)——对象的组合
重要概念: 1.在设计线程安全类的过程中,需要包含以下三个基本要素: (1)找出构成对象状态的所有变量. (2)找出约束状态变量的不变性条件. (3)建立对象状态的并发访问管理策略. 2.
- JAVA并发编程学习笔记------多线程调优
1. 多线程场景下尽量使用并发容器代替同步容器 (如ConcurrentHashMap代替同步且基于散列的Map, 遍历操作为主要操作的情况下用CopyOnWriteArrayList代替同步的Lis ...
- Java并发编程学习笔记(一)——线程安全性
主要概念:线程安全性.原子性.原子变量.原子操作.竟态条件.复合操作.加锁机制.重入.活跃性与性能. 1.当多个线程访问某个状态变量并且其中有一个线程执行写入操作时,必须采用同步机制来协同这些线程对变 ...
- [转]JAVA并发编程学习笔记之Unsafe类
1.通过Unsafe类可以分配内存,可以释放内存:类中提供的3个本地方法allocateMemory.reallocateMemory.freeMemory分别用于分配内存,扩充内存和释放内存,与C语 ...
- java并发编程学习笔记(一)初识并发原子性
1.并发的意义 现在是一个多核的时代,并发的存在意义就是为了能够充分利用多核计算机的优势,提高程序的运行效率: 2.并发的风险 竞争-----多个线程对内存数据数据进行读写操作时,对数据处理结果的一个 ...
随机推荐
- python制作wifi破解(跑字典(单线程))
很鸡巴简单,接上一篇文章 import pywifi import sys import time from pywifi import const def test_wifi_connect(pas ...
- burpsuite截断上传webshell
1.先设置好代理127.0.0.1 8080 2.开启截断模式 3.上传文件会被burp截断 4.在hex下找到你上传的webshell的16进制编码 5.把.后面的源码改为00 点击forward上 ...
- bzoj:3400 [Usaco2009 Mar]Cow Frisbee Team 奶牛沙盘队
Description 农夫顿因开始玩飞盘之后,约翰也打算让奶牛们享受飞盘的乐趣.他要组建一只奶牛飞盘 队.他的N(1≤N≤2000)只奶牛,每只部有一个飞盘水准指数Ri(1≤Ri≤10000 ...
- 2017 ICPC/ACM 沈阳区域赛HDU6223
Infinite Fraction Path Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 262144/262144 K (Java ...
- vim与外部文件的粘帖复制
vim与外部文件的粘帖复制 ubuntu默认vim是不支持从外部文件与vim之间的粘帖复制,vim有自己的剪切版,分别是”0-”9,”-,”8,”+,”:,”/,”%,”i,这些都是vim的寄存器,可 ...
- sql中查询同一列所有值出现的次数
尊重原创:http://blog.csdn.net/love_java_cc/article/details/52234889 有表如下table3: 需要查询country中各个国家出现的次数 SQ ...
- cesium编程入门(五)绘制形状
通过Entity添加形状 先来看一个添加立方体的例子 var viewer = new Cesium.Viewer('cesiumContainer'); var redBox = **viewer. ...
- java实现死锁的demo
死锁 只有当t1线程占用o1且正好也需要o2,t2此时占用o2且正好也需要o1的时候才会出现死锁,(类似于2个人拿着两个筷子吃饭,都是需要对方的一根筷子才能吃) 以下代码t1线程占用o1,并且获取到o ...
- 解决方案 git@github.com出现Permission denied (publickey)
ubentu 13.10 git version 1.8.3.2 解决方案:ssh -T git@github.com出现Permission denied (publickey).的问题 今天的任 ...
- 将本地的项目导入到github仓库总结lxw
关键步骤: 第一:git clone https://github.com/lxw18231857001/demo-.git #把github上面的仓库克隆到本地 本地项目文件夹下 ...