Это может показаться глупым, но я не могу получить этот. VolatileCachedFactorizer хранит экземпляр OneValueCache и повторно инициализирует его при каждом вызове. Не должно ли это назначение выполняться в синхронизированном блоке?
@Immutable
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, factors); // is this line ok?
}
encodeIntoResponse(resp, factors);
}
}
Переменная cache
volatile
. Это означает, что происходит действие записи - до последующего действия чтения, которое наблюдает за письменным значением. Поэтому объект, о котором идет речь, был безопасно опубликован в другой поток, и дальнейшая синхронизация не требуется.
Обратите внимание, что поскольку OneValueCache
является неизменным классом, даже без летучих ("публикация через гонку данных"), код по-прежнему будет потокобезопасным в том смысле, что поток, если он когда-либо наблюдает объект, будет гарантирован полностью соблюдайте его. Однако без volatile
нет гарантии, что ссылка на объект никогда не будет наблюдаться другим потоком.
OneValueCache
не является атомарным, не может ли быть случай, когда два потока одновременно OneValueCache
свой объект и какой из них назначается для ссылки на cache
непредсказуемо?