第3章-对象的共享

可见性


在没有同步的情况下.编译器,处理器以及运行时等都可能对操作的执行顺序进行一些意想不到的调整. 在缺乏足够同步的多线程程序中,要想对内存操作的执行顺序进行判断,几乎无法得出
正确的结论.


失效数据


非原子的64位操作


加锁与可见性


我们可以进一步理解为什么在访问某个共享且可变的变量时要求所有线程在同一个锁上同步,就是为了确保某个线程写入该变量的值对于其他线程来说都是可见的,否则,如果一个线程在未
持有正确锁的情况下读取某个变量,那么读到的可能是一个失效值.
加锁的含义不仅仅局限于互斥行为,还包括内存可见性,为了确保所有线程都能看到共享变量的最新值,所有执行读操作或者写操作的线程都必须在同一个锁上同步.


volatile变量
volatile变量可以用来确保将变量的更新操作通知到其他线程,volatile变量不会被缓存在寄存器或者对其他处理器不可见的地方,因此在读取volatile类型的变量时总会返回最新写入的值


在访问volatile变量时不会执行加锁操作,因此也就不会使执行线程阻塞,因此volatile变量时一种比synchronized关键字更轻量级的同步机制.


仅当volatile变量能简化代码的实现以及对同步策略的验证时,才应该使用他们,如果再验证正确性时需要对可见性进行复杂的判断,那么就不要使用volatile变量.volatile变量的正确使用
方式包括: 确保他们自身状态的可见性,确保他们所引用对象的状态的可见性,以及标识一些重要的程序生命周期事件的发生(例如,初始化或关闭)


加锁机制即可以确保可见性又可以确保原子性, 而volatile变量之恩给你确保可见性.


当且仅当满足以下所有条件时,才应该使用volatile变量:
对变量的写入操作不依赖变量的当前值,或者你能确保只有一个单线程更新变量的值.
该变量不会与其他状态变量一起纳入不变性条件中.
在访问变量时不需要加锁


发布与逸出




线程封闭


当访问共享的可变数据时,通常需要使用同步. 一种避免使用同步的方式就是不共享数据. 如果仅在但现场内访问数据,就不需要同步. 这种技术被称为线程封闭. 他是实现线程安全性的最
简单方式之一. 当某个对象封闭在一个线程中时,这种用法将自动实现线程安全性, 即使被封闭的对象本身不是线程安全的.


在Swing中大量使用了线程封闭技术. Swing的可视化组件和数据模型对象都不是线程安全的,Swing通过将他们封闭到Swing的事件分发线程中来实现线程安全性.即除了事件线程之外的其他
线程中就不能访问这些对象.
Java语言及其核心库提供了一些机制来帮助维持线程封闭性, 例如局部变量和ThreadLocal类.


Ad-hoc线程封闭: 维护线程封闭性的职责完全由程序实现来承担.


栈封闭: 是线程封闭的一种特例,在栈封闭中,只能通过局部变量才能访问对象.


ThreadLocal类: 这个类能是线程中的某个值与保存值的对象并联起来. ThreadLocal提供了get与set等访问接口或方法,这些方法为每个使用该


不变性
满足同步需求的另一种方法是使用不可变对象(Immutable Object). 


不可变对象一定是线程安全的.
不可变对象很简单. 他们只有一种状态,并且该状态由构造函数来控制.
当满足以下条件时, 对象才是不可变的:
对象创建以后其状态就不能修改;
对象的所有域都是final类型;
对象是正确创建的(在对象的创建期间, this引用没有逸出)













































评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值