Вопрос

Это то, как мой код выглядит:

private boolean[] isInitialized = new boolean[COUNT];

private void ensureInitialized(int i) {
    if (! isInitialized[i]) {
        initialize(i);
        isInitialized[i] = true;
    }
}

Теперь я хочу иметь это в безопасности. Я знаю, что двойная проверка в Java - это «3Vilness !! 1», но с ensureInitialized Может быть названо очень часто, я не хочу, чтобы это было синхронизировано. Так что я думаю сделать это:

private boolean[] isInitialized = new boolean[COUNT];

private void ensureInitialized(int i) {
    if (! isInitialized[i]) {
        synchronized (this) {
            if (! isInitialized[i]) {
                initialize(i);
                isInitialized[i] = true;
            }
        }
    }
}

Теперь, что мне нужно сделать, чтобы сделать это на самом деле безопасным потоком?
Некоторые подзаимства:

  • Изготовление isInitialized Волатильный не нужен, так как переменная не изменилась, верно?
  • Элементы массива изменяются, как я могу сделать эти волатильные?
  • Есть ли в целом лучшие способы сделать это?

(Также обратите внимание, что это метод экземпляра, поэтому статический инициализатор не будет работать)

Это было полезно?

Решение

Обратите внимание, что Java внедрение двойной проверки называется «разбитым рисунком», потому что она была доказана, как проваливается (например, см. http://www.cs.umd.edu/~pugh/java/memorymodel/doublecheckedlocking.html.). Работать, просто используйте атомную операцию. Следуйте образец, как построить потоков Safe Singleton:

static AtomicReferenceArray<Boolean> instance = 
   new AtomicReferenceArray<Boolean>(COUNT);

private void ensure(int i)
{
    if(!instance.get(i) )
    {
        synchronized(this){
        if( !instance.get(i) ){
           initialize(i);
           instance.set(i, true);
        }
    }
}

Другие советы

Вы также можете рассмотреть вопрос Suppliers.memoize(Supplier<T> delegate) от Гуава Библиотека.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top