线程安全性
如果当多个线程访问同一个可变的状态变量时没有使用合适的同步,那么程序就会出现错误,有三种方式可以修复这个问题:
. 不再线程之间共享该状态变量
. 将状态变量修改为不可以变的变量
. 再访问状态变量时使用同步
当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程如何交替执行,并且再主调代码中不需要任何额外的同步或者协同,这个类都能表现出正确的行为,那么就称这个类时线程安全的
原子性
当某个计算的正确性取决于多个交替执行时序时,就会发生竞态条件。竞态条件会影响类执行的正确性,后续就需要引入原子性理论了
假定有两个操作A和B,如果从执行A的线程来看,当另一个线程执行B时,要么将B完全执行完,要么完全不执行B,那么A和B对彼此来说就是原子的,原子操作就是指,对于访问同一个状态的所有操作(包括该操作本身)来说,这个操作是一个以原子方式执行的操作。
锁机制
为了支持原子性的业务实现,Java提供了一种内置的锁机制来实现,同步代码块(Synchronized)
该锁还包含了可重入的机制来实现
Volatile变量
volatile变量是一种被削弱的同步机制
应用场景,仅当volatile变量能简化代码的实现以及对同步策略的验证时,才应该使用它们,如果在验证正确性时需要对可见性进行复杂的判断,那么就不要使用volatile变量。volatile变量的正确使用方式包括,确保他们自身状态的可见性,确保他们所引用对象的状态的可见性,以及标识一些重要的程序生命周期实践的发生
线程封闭
当访问共享的可变数据时,通常需要使用同步,一种避免使用同步的方法就是不共享数据,如果仅在单线程内访问数据就不需要同步,这种技术就是线程封闭,维持线程封闭有两种方式Ad-hoc封闭和栈封闭
Ad-hoc,即使用代码的方式实现线程封闭,如volatile变量实现
栈封闭用来在线程内部使用或线程局部使用来实现
ThreadLocal
维持线程封闭更规范的方式就是使用ThreadLocal
ThreadLocal对象通常用于防止对可变的单实例变量或全局变量进行共享,如jdbc连接参数可以存储在ThreadLocal中
对象的不变性
当满足一下条件时,对象才是不可变的:
. 对象创建以后其状态就不能修改。
. 对象所有域都是final类型
. 对象时正确创建的(在对象的创建期间,this引用没有逸出)
安全发布对象的常用模式
要安全发布一个对象,对象的引用以及对象的状态必须同时对其他线程可见。一个正确构造的对象可以通过一下方式来安全的发布:
. 在静态初始化函数中初始化一个对象引用
. 将对象的引用保存到volatile类型的域或者AtomicReferance对象中
. 将对象的引用保存到某个正确构造对象的final类型域中
. 将对象的引用保存到一个由锁保护的域中
网友评论