Может ли поток во время гонки данных прочитать начальное нулевое значение переменной volatile?особенно когда ему присваивается ненулевое значение в конструкторе? - PullRequest
4 голосов
/ 03 декабря 2010
  • Что меня озадачивает, так это.

Java-документ HashEntry в ConcurrentHashMap (jdk1.6.0_16)

... Поскольку поле значения является изменчивым, а неИ, наконец, для несинхронизированного считывателя допустимо использовать модель памяти Java, чтобы при чтении через гонку данных видеть нулевое значение вместо исходного значения.Хотя переупорядочение, ведущее к этому, вряд ли когда-либо произойдет, метод Segment.readValueUnderLock используется в качестве резервной копии на случай, если нулевое (предварительно инициализированное) значение когда-либо будет замечено в методе несинхронизированного доступа.

  • здесь - реализация метода get ConcurrentHashMap # Segment

    
    V get(Object key, int hash) {
            if (count != 0) { // read-volatile
                HashEntry e = getFirst(hash);
                while (e != null) {
                    if (e.hash == hash && key.equals(e.key)) {
                        V v = e.value;
                        if (v != null)
                            return v;
                        return readValueUnderLock(e); // recheck
                    }
                    e = e.next;
                }
            }
            return null;
        }
    
  • И readValueUnderLock


V readValueUnderLock(HashEntry e) {
        lock();
        try {
            return e.value;
        } finally {
            unlock();
        }
    }
  • Основываясь на моем прочтении и понимании, каждый поток будет читать актуальное значение переменной volatile.

  • Так, когда поток прочитает начальное нулевое значение?особенно в HashEntry, где значение присваивается до завершения конструктора.(Также обратите внимание, что ссылка HashEntry никогда не ускользает от своего конструктора.)

  • Я в замешательстве, может кто-нибудь объяснить вышеупомянутый java-документ HashEntry в ConcurrentHashMap (jdk1.6.0_16).и почему требуется дополнительная блокировка?

Ответы [ 2 ]

3 голосов
/ 03 декабря 2010

Когда была выпущена Java 1.5, в JMM было условие, согласно которому HashEntry может быть частично инициализирован.То есть, когда поток помещается в карту, HashEntry создается и назначается в качестве ссылки либо на ведро, либо на член коллизии.В то время значение записи, возможно, не было назначено для просмотра другими потоками.

CHM предполагает, что если запись не пуста, то значение не должно быть пустым, поэтому readValueUnderLock был введен как отказоустойчивый

Я спросил Д.Л. об этой точной ситуации, и он сказал, что, несмотря на возможность этого, это никогда не должно происходить.Он также сказал, что с версии 1.6 такой проблемы не будет.

0 голосов
/ 03 декабря 2010

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

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

...