Java: энергозависимый массив для публикации изменений данных

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

То есть, если ключ один и тот же, структура, на которую он ссылается, всегда будет вести себя одинаково. На самом деле, ключ неизменяемый final, а значение, на которое указывает ссылка, является final и/или потокобезопасным.

Допустим, у меня есть изменчивая ссылка на базовый изменчивый массив ссылок в моей пользовательской хэш-карте. Мой алгоритм хеш-карты для этого массива использует элемент ar.length в качестве модуля, поэтому, если в функции get вызывающий объект увидит нетекущий массив, все его ссылки будут по-прежнему правильными и по-прежнему будут подчиняться хеш-слотам, поэтому, если он удается без мьютекса получить ненулевое значение, это правильно.

Мой план заключается в том, что всякий раз, когда получение терпит неудачу, вызывающая сторона затем создает правильное значение для ключа, выполняет размещение, которое выполняет блокировку по отношению к другим размещениям, и заполняет объект в массиве. Непосредственно перед выходом из критической секции код put переназначает поле энергозависимого массива «ar» самому себе, надеюсь, в качестве сообщения компилятору и компилятору горячей точки, чтобы создать забор относительно получения, которые используют ссылку на энергозависимый массив для поиска хешированного значения.

Это будет работать до тех пор, пока компилятор не отключит присваивание "ar = ar":

private volatile Object[] ar;

public Object get (Object key)
{
    Object[] ar = this.ar;
    // get the value from the correct hash slot
}

public synchronized Object put (Object key, Object val) {
{
    ... stuff a new object into the correct hash slot

    ar = ar;             // will the compiler truly compile this statement with 
                         // normal volatile fencing relative to the get function??

    ... if a race condition causes a value to already be mapped, return and use that
    ... rather than the one we created and passed to put (different than normal put
    ... contract)
}

person Andy Nuss    schedule 15.01.2012    source источник


Ответы (1)


Волатильная запись не может быть оптимизирована, так что да, вы получите здесь гарантии памяти. И поскольку чтение значения из массива также (по крайней мере, концептуально) означает, что вы читаете изменчивую переменную массива, вы также должны получить одно гарантированное изменчивое чтение.

Итак, хотя это должно работать - если вы используете Hotspot, обычный способ сделать это - с sun.misc.Unsafe - вы можете посмотреть параллельные коллекции в Java5 и выше, где этот шаблон демонстрируется достаточно часто. (И да, мы все можем рассчитывать на получение массивов энергозависимых элементов в будущем — на самом деле Дуг Леа и Ко работают над спецификацией для этого, но понятия не имеют, как далеко они продвинулись.)

Хотя вопрос в том, почему вы реализуете это самостоятельно - есть неблокирующая хэш-карта Клиффа, которая имеет довольно сильные гарантии правильности (на самом деле, они проверили ее с помощью CHESS для одного, и многие люди посмотрели на базовый конечный автомат) и отличная производительность по сравнению с ConcurrentHashMap из ЖДК.

И уж точно быстрее, чем синхронизированная операция put.

person Voo    schedule 15.01.2012