不变性

不可变对象一定是线程安全的

那么什么是不可变对象呢?

当满足一下条件时,对象才是不可变的。

  • 对象创建以后其状态就不能修改
  • 对象的所有域都是final类型
  • 对象是正确创建的(在对象的创建期间,this引用没有逸出)

我们回到之前因数分解的例子,通过构造一个不可变类来实现同步:

class OneValueCache{
    private final BigInteger lastNumber;
    private final BigInteger[] lastFactors;

    public OneValueCache(BigInteger i, BigInteger[] factors){
        lastNumber = i;
        lastFactors = Arrays.copyOf(factors, factors.length);
    }

    public BigInteger[] getFactors(BigInteger i){
        if (lastNumber == null || !lastNumber.equals(i)) {
            return null;
        } else {
            return Arrays.copyOf(lastFactors, lastFactors.length);
        }
    }
}

public class VolatileCachedFactorizer implements Servlet{
    private volatile OneValueCache cache = 
        new OneValueCache(null,null);

    public void service(ServletRequest req, ServletResponse resp){
        BigInteger i = extractFromRequest(req);
        BigInteger[] factors = cache.getFactors(i);
        if (factors == null) {
            factors = factor(i);
            cache = new OneValueCache(i, value);
        }
        encodeIntoResponse(resp, factors); 
    }
}

我们可以看到OneValueCache为一个不可变类,并且我们在创建时,使用volatile关键字声明,这样保证了线程安全性和可见性。

但要注意的一点是:
如果final类型的域所指向的是可变对象,那么在访问这些域所指向的对象的状态时仍然需要同步

public final class ThreeStooges {
  private final Set stooges = new HashSet();

  public ThreeStooges() {
    stooges.add("Moe");
    stooges.add("Larry");
    stooges.add("Curly");
  }

  public boolean isStooge(String name) {
    return stooges.contains(name);
  }

  public synchronized Set getStooges(){
    return stooges;
  }
}

如上,stooges变量为可变对象,因此,如果我们需要对其访问时,需要加上synchronized关键字来保证同步。

你可能感兴趣的:(不变性)