2014-09-14 3 views
2

Мне интересно, гарантируется ли эта идея кэширования для работы:Безопасна ли эта кеширующая нить?

@RequiredArgsConstructor @Getter class CacheEntry { 
    static CacheEntry get(String string, int start) { 
     int hash = string.hashCode()^start; // or something better 
     int index = hash & (cache.length-1); 
     CacheEntry result = cache[index]; 
     if (result!=null && result.matches(string, start)) return result; 
     result = new CacheEntry(string, start, computeSomething(string, start)); 
     cache[index] = result; 
     return result; 
    } 

    private boolean matches(String string, int start) { 
     if (string.equals(this.string)) return false; 
     if (start == this.start) return false; 
     return true; 
    } 

    private static ImmutableSomething computeSomething(String string, int start) { 
     ... 
    } 

    private static final CacheEntry[] cache = new CacheEntry[256]; 

    private final String string; 
    private final int start; 

    private final ImmutableSomething something; 
} 

Аннотации приходят из lombok. Только представьте, что каждый делает то, что говорит его имя.

Целью является сохранение вызовов до computeSomething, а также для минимизации распределения.

Кэширование не синхронизировано ни по локальной сети. Нет никакой гарантии, что один поток увидит обновления, сделанные другим. Это приемлемо. Также нет гарантии, что один поток не перезаписывает записи из другого. Это тоже приемлемо.

В небольшом тесте я написал, что это привело к хорошему ускорению по сравнению с sane caching alternatives. Моя забота о правильности: может ли когда-нибудь произойти, что поток видит недопустимую запись (например, один содержит неправильный something)?

+0

Это выглядит правильно для меня. Назначение ссылки объекта на переменную является атомной операцией, и вы не заботитесь об отсутствии гарантии видимости памяти, поэтому она выглядит нормально (за исключением очевидных проблем с компиляцией). –

+0

@JBNizet Проблемы с компиляцией пропали. Я вижу, что писать что-нибудь немного больше без IDE - это плохая идея. – maaartinus

ответ

3

Это будет работать до тех пор, пока CacheEntry является надлежащим неизменяемым объектом (в отличие от простого эффективного объекта). Это связано с тем, что неизменяемые объекты могут быть безопасно опубликованы без синхронизации, а назначение объектных ссылок является атомарным.

Другими словами, было бы небезопасно, если CacheEntry не является полностью неизменяемым, так как потребительский поток может видеть объект, который не полностью сконструирован. Кроме того, если то, что кэшируется, является примитивными типами, чьи назначения не являются атомарными (double, long), потребительский поток мог видеть мусор (половину назначенных значений).

EDIT:
Согласно Java Concurrency in Practice, объект может быть безопасно опубликована без синхронизации, если:

  • Его состояние не может быть изменен после строительства
  • Все его поля объявлены final
  • Это (ключевое слово не исчезает во время строительства)
+0

Я предполагаю, что «эффективно неизменными» вы имеете в виду такие вещи, как «Коллекции.немодифицируемые ...», правильно? – maaartinus

+0

Считаете ли вы, что поле 'final long' в' CacheEntry' или 'ImmutableSomething' может быть проблемой? Надеюсь, нет, из-за «финала». – maaartinus

+0

@maaartinus: Да, вы можете обратиться к JCiP за точными условиями: http://books.google.co.uk/books?id=EK43StEVfJIC&pg=PT64&lpg=PT64&dq=java+concurrency+in+practice+immutable+object&source= бл & отс = uoUxD2yQlw & сиг = 7ZzT-gyHLTstKxJyd5TJvKVsFcg & гл = еп & са = Х & е = v9sVVN_eAdDsaOnigsAG & вед = 0CF8Q6AEwBw # v = OnePage & д = Java% 20concurrency% 20in% 20practice% 20immutable% 20object & F = ложь Я добавил отрывок в ответ –

Смежные вопросы