设计线程安全类的三个基本要素:
1、构成对象状态的所有变量;
2、约束状态变量的不变性条件;
3、建立对象状态的并发访问管理策略
在设计线程安全类需要对整个程序进行安全分析以判断每个类是否是安全的,这样难以确保其是线程安全的。为了提高线程安全的分析效率可以使用封装技术对多个对象(包括线程安全的和非线程安全对象)进行封装,这样只要封装类的对象是线程安全的就可以确保多个线程可以安全的访问被封装的所有资源。
要设计一个线程安全的类首先要分析以下几点:
1、构成该对象的状态,哪些是可变的哪些是不可变的?
在分析对象有哪些状态时首先要确保该对象的这些状态由哪些变量组成,以及确定 哪些状态是该发布的哪些是应该被封装的
2、对象状态的所有权的归属
对象的所有权和其封装性有很大的关联性,一般来说对象封装它拥有的所有状态就拥有了其状态的所有权。然后就可以规定用哪种加锁协议来保证变量状态的完整性,或者说是可以保证构造一个完整的安全对象。在java中采用的是所有权分离的方式,比如说容器类管理对象,容器类只拥有其自身的状态,客户代码则拥容器中对象的状态
3、依赖状态的操作
这里指包含基于状态先验条件的操作。如果先验条件不满足则直接抛异常或者失败来处理。
4、同步需求分析
收集同步需求主要是为了保证在并发过程中类的不变性条件不会被破坏,从而确定类的线程安全性。
如何安全的访问线程不安全的对象。
四种方式:
1、对整个对象进行加锁(性能太低)
2、以单线程的方式进行访问(jdbc数据库连接池的处理方式)
3、将线程不安全的对象委托给线程安全的容器进行管理
通过java提供的同步工具类来进行处理,即将非线程安全的类委托给线程安全的容器进行管理,比如ConcurrentMap、ConcurrentHashMap。但是应该注意委托失效和添加新的功能时不是对同一个对象加锁无法保证同步的问题。
4、实例封闭
其中实例封闭的方式就是将线程不安全的对象封装在一个线程安全类的实例的私有成员中或者局部变量中,切记这里是封装,因此被封装对象的作用域最多是限定在线程安全类的实例中。然后通过内置锁的方式保证所有线程以同步的方式来访问这个实例,从而实现将非线程安全的类转换成线程安全的类。