如果当多个线程访问同一个可变的状态变量时没有使用合适的同步,那么程序就会出现错误。有三中方式可以修复这个问题:
1. 不在线程之间共享该状态变量
采用线程封闭技术,实现状态变量不在线程之间进行共享。线程封闭技术有三个实现原理:
1. Ad-hoc线程封闭
其实就是维护线程封闭性的职责完全由程序实现来承担,该方式的线程封闭是非常脆弱的
2. 栈封闭
在栈封闭中。只能通过局部变量才能访问对象,局部变量的固有属性之一就是封闭在执行环境当中,它们位于执行线程的栈中,其他线程无法访问这个栈。该方法其实也就是使用局部变量来实现线程的安全。
3. ThreadLocal类
维持线程封闭性的一种更规范方法是使用ThreadLocal,这个类能使线程中的某个值与保存值的对象关联起来。ThreadLocal提供了get与set等访问接口和方法,这些方法为每个使用该变量的线程都存有一份独立的副本,因此get总是能返回当前执行线程在调用set时设置的最新值。
private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>() {
pulic Connection initialValue() {
return DriverManager.getConnection(DB_URL);
}
};
public static Connection getConnection() {
return connectionHoler.get();
}
将状态变量修改为不可变的变量
不可比对象一定是线程安全的
。所谓不可变对象,其实就是如果某个对象在被创建后其状态就不能被修改,那么这个对象就称为不可变对象。线程安全性是不可变对象的固有属性之一。因为不可变对象在创建之后只会有一种状态,不会发生变化,所以一定是线程安全的。要使一个对象成为不可变对象,需要满足以下三个条件:- 对象创建后其状态就不能修改
- 对象的所有与都是final类型的
- 对象被正确地创建了(在对象的创建期间,this引用没有逸出)。
其中,如果对象从技术上来看是可变的,但其状态在对象被创建后就不会再变化,那么把这种对象成为“事实不可变对象”
,这些对象不需要满足上述的三个条件,在这些对象发布之后,程序只需要将它们视作不可变的对象即可。
在访问状态变量时使用同步
在大多数情况下,以上两种保证线程安全性的方式不足以满足我们的开发需求,这是,我们就需要在访问共享的状态变量时,使用同步机制,保证线程的安全性。