不可變對象一定是線程安全的
那么什么是不可變對象呢叭首?
當(dāng)滿足一下條件時(shí),對象才是不可變的焙格。
- 對象創(chuàng)建以后其狀態(tài)就不能修改
- 對象的所有域都是final類型
- 對象是正確創(chuàng)建的(在對象的創(chuàng)建期間,this引用沒有逸出)
我們回到之前因數(shù)分解的例子吴旋,通過構(gòu)造一個(gè)不可變類來實(shí)現(xiàn)同步:
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為一個(gè)不可變類荣瑟,并且我們在創(chuàng)建時(shí)摩泪,使用volatile關(guān)鍵字聲明,這樣保證了線程安全性和可見性见坑。
但要注意的一點(diǎn)是:
如果final類型的域所指向的是可變對象,那么在訪問這些域所指向的對象的狀態(tài)時(shí)仍然需要同步
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變量為可變對象熊楼,因此,如果我們需要對其訪問時(shí)鲫骗,需要加上synchronized關(guān)鍵字來保證同步。