Java并发编程学习记录#4
来源:互联网 发布:软件测试英文简历 编辑:程序博客网 时间:2024/06/11 08:01
组合对象
探讨一些构造类的模式,使得类更容易成为线程安全的。
设计线程安全的类
设计线程安全的类的过程应该包含三个方面:
- 确定对象状态是由哪些变量构成–变量;
- 确定限制对象状态的不变约束–不变约束;
- 制定一个管理并发访问对象状态的策略–后验条件。
不变约束:用来判定一个状态是合法的还是不合法的,比如int的取值范围,是施加在状态上的约束;
后验条件:指出某种状态转变是否合法,是施加在状态操作上的约束;
上述二者需要引入额外的同步和封装。
组合:将一个对象封装到另一个对象内部。
组合使得被封装对象的全部访问路径都是可知的,这相比让整个应用系统 访问对象来说,更容易对访问路径进行分析,然后再和各种适当的锁相结合,可以确保程序能以线程安全的方式使用其它非线程安全的对象。
在并发领域,组合是为保证线程安全的的一个线程限制。
Java监视器模式
一种线程限制原则,遵循该原则的对象封装了所有的可变状态,并使用对象的内部锁来保护。例如:
public class PrivateLock { private final Object myLock = new Object(); @GuardedBy("myLock") Widget widget; void someMethod() { synchronized (myLock) { // Access or modify the state of widget } }}
委托线程安全
一些由线程安全的组件组合而成的组件未必是线程安全的。比如这些线程安全的子组件有依赖性。见代码:
public class NumberRange { // INVARIANT: lower <= upper private final AtomicInteger lower = new AtomicInteger(0); private final AtomicInteger upper = new AtomicInteger(0); public void setLower(int i) { // Warning -- unsafe check-then-act if (i > upper.get()) throw new IllegalArgumentException("can't set lower to " + i + " > upper"); lower.set(i); } public void setUpper(int i) { // Warning -- unsafe check-then-act if (i < lower.get()) throw new IllegalArgumentException("can't set upper to " + i + " < lower"); upper.set(i); } public boolean isInRange(int i) { return (i >= lower.get() && i <= upper.get()); }}
若有两个线程,同时,分别访问setLower和setUpper,则可能出现线程安全问题。
只有当一个类有多个彼此独立的 线程安全的状态变量组合而成,且类的操作不包含任何无效的状态转换时,才可以将线程安全委托给这些状态变量。
向已有的线程安全类中添加功能
重用Java自带的线程安全类,要好于创建一个新的,无论在难度,风险或是维护上。比如对一个List添加功能:缺少则添加。即先判断list中是否有此元素,无,则添加。此时涉及到了检查-执行这一复合操作,按照之前同步策略,是可以在此操作上加锁将其变成原子性操作的,但是因为源码我们没法修改,只能找别的方式。这里,组合,或是继承都可以。比如继承:
@ThreadSafepublic class BetterVector <E> extends Vector<E> { // When extending a serializable class, you should redefine serialVersionUID static final long serialVersionUID = -3963416950630760754L; public synchronized boolean putIfAbsent(E x) { boolean absent = !contains(x); if (absent) add(x); return absent; }}
不过组合(这里只指原功能的线程安全委托给子组件)的话,需要一些其它的操作,不能直接在方法上同步。因为Q1操作无法保证helper类封装的list的其它方法和putif..的同步问题。
@NotThreadSafe//Q1操作,不安全class BadListHelper <E> { public List<E> list = Collections.synchronizedList(new ArrayList<E>()); public synchronized boolean putIfAbsent(E x) { boolean absent = !list.contains(x); if (absent) list.add(x); return absent; } ...}@ThreadSafeclass GoodListHelper <E> { public List<E> list = Collections.synchronizedList(new ArrayList<E>()); public boolean putIfAbsent(E x) { synchronized (list) { boolean absent = !list.contains(x); if (absent) list.add(x); return absent; } } ...}
还有另一种组合方式,就是将所组合的对象中所有存在风险的方法都加上内部锁,而不用依赖子组件对象是否线程安全。
@ThreadSafepublic class ImprovedList<T> implements List<T> { private final List<T> list; public ImprovedList(List<T> list) { this.list = list; } public synchronized boolean putIfAbsent(T x) { boolean contains = list.contains(x); if (contains) list.add(x); return !contains; } public synchronized boolean add(T e) { return list.add(e); } public synchronized boolean remove(Object o) { return list.remove(o); } .....other alike methods..
写好文档,非常重要!
//待下篇
主要参考自_ Java Concurrency in Practice
- Java并发编程学习记录#4
- Java并发编程学习记录#1
- Java并发编程学习记录#2
- Java并发编程学习记录#3
- 并发编程学习记录
- 并发编程学习记录(一)
- 随笔记录-java并发编程
- Java并发编程学习
- java并发编程学习4--forkJoin
- java并发编程学习(4)
- 《Java 7 并发编程指南》学习概要 (4) 并发集合
- java并发编程实践学习
- Java并发编程学习2
- Java多线程并发编程学习
- java的并发编程学习
- Java并发编程学习路线图
- JAVA并发编程学习笔记
- Java并发编程深入学习
- Swift中使用正则表达式
- Tortoisegit安装和使用教程
- 图片和文字样式
- 程序员跳槽全攻略
- 1039. 到底买不买(20)
- Java并发编程学习记录#4
- Spark学习笔记(8)源码解读之RDD生成全生命周期
- @Override is not allowed when implementing interface method
- Linux云服务器安装tomcat
- 美团秋招笔试题--可乐瓶盖
- tensorflow实现Linear Regression
- hbase简介
- Eclipse 的单步调试
- 51Nod-1033-骨牌覆盖 V2