Java并发

不变性

2017-04-12  本文已影响13人  大海孤了岛
不可变对象一定是线程安全的

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

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

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

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<String> stooges = new HashSet<String>();

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

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

  public synchronized Set<String> getStooges(){
    return stooges;
  }
}

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

上一篇 下一篇

猜你喜欢

热点阅读