1.怎么设计线程安全的类?
a.找出构成对象状态的所有变量
b.找出约束状态变量的不变性条件
c.建立对象状态的并发访问管理策略
对于b点大家肯定有疑惑怎么找出状态变量不变性条件,举个例子假如设计一个一天的时间点,时间只能是24个小时,60分钟,60秒,三个变量这是它不变性条件,找出不变性的目的是收集同步需求,保证不变性不会再并发情况下不被破坏,还有一个点必须提一下,先验性(空对象不能获取它的属性,肯定要先判断它是否为空),也可以叫依赖状态的操作,要保证不变性条件。
c点大家可以参考JAVA并发秉承实战笔记02
2.JAVA监视器模式:遵循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
}
}
}
3.对象的组合
1.使用并发容器类来实现对象组合的线程安全比如:ConcurrentMap,CopyOnWriteArrayList、CopyOnWriteLinkList
2.使用JAVA监视器模式
注:如果一个类是由多个独立且线程安全的状态变量组成,并且在所有的操作中都包含无效状态的装换,那么可以将线程安全线委托给底层的状态变量,此类不是线程安全的
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());
}
}
NumberRange线程安全性人物给“AtomicInteger”,不变性条件: lower <= upper,上述例子即使 lower ,upper是线程安全的,但是两个变量存在不变性条件,所以NumberRange不是线程安全的。
4.加锁机制(不使用同一把锁导致线程不安全)
@NotThreadSafe
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;
}
}
修复完的代码
@ThreadSafe
class 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;
}
}
}
当锁发生变化时,导致线程不安全
public class ChangeLock {
private String lock = "lock";
private void method(){
synchronized (lock) {
try {
System.out.println("当前线程 : " + Thread.currentThread().getName() + "开始");
lock = "change lock";
Thread.sleep(2000);
System.out.println("当前线程 : " + Thread.currentThread().getName() + "结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
final ChangeLock changeLock = new ChangeLock();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
changeLock.method();
}
},"t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
changeLock.method();
}
},"t2");
t1.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
}
}
在现有的线程安全类扩展功能方式:继承、组合
@ThreadSafe
public 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;
}
}
@ThreadSafe
public class ImprovedList<T> implements List<T> {
private final List<T> list;
/**
* PRE: list argument is thread-safe.
*/
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;
}
//...
}
将同步策略文档化,有相应的文档做说明