对象的共享-不变性

前面介绍线程安全性时提到,保证线程安全性还有一种方式,就是使用不可变对象

那么怎样保证对象不可变?

  1. 对象创建以后其状态不能改变。
  2. 对象的所有域都是final类型。
  3. 对象是被正确创建的(没有this引用逸出)。

示例

在不可变对象基础上构建不可变类

1
2
3
4
5
6
7
8
9
10
11
12
@Imutable
public final class ThreePeople{
private final Set<String> people = new HashSet<>();
public ThreePeople(){
people.add("Tom");
people.add("Mary");
people.add("Jack");
}
public boolean isContains(String name){
return people.contains(name);
}
}

使用volatile 发布不可变对象

对于在访问和更新多个相关变量时出现的竞态条件问题,可以通过将这些变量全部保存在一个不可变对象中消除。不可变对象不必担心一个线程获得对象的引用后,另一个线程会修改对象的状态。如果想更新这些变量,可以重新新建这个不可变对象。

缓存最新的一次计算结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
@Immutable
class OneValueCache {
private final Long number;
private final Long result;
OneValueCache(Long number, Long result) {
this.number = number;
this.result = result;
}
public Long getNumber() {
return number;
}
public Long getResult() {
return result;
}
}
class OneValueTest{
//使用volatile保证多线程始终能看到oneValueCache最新的结果
private volatile OneValueCache oneValueCache = new OneValueCache(null, null);
public Long getResult(Long number) {
Long cacheNumber = oneValueCache.getNumber();
if (number.equals(cacheNumber)) {
Long result = oneValueCache.getResult();
return result;
}
Long result = cal(number);
//缓存不存在时,新建OneValueCache缓存,这将覆盖之前的计算结果
oneValueCache = new OneValueCache(number, result);
return result;
}
//一些复杂的计算
private Long cal(Long number) {
return ++number;
}
}