Как устранить ошибку поиска Последовательность вызовов java.util.concurrent.ConcurrentHashMap может не быть атомарной

Привет, я получаю сообщение об ошибке «Последовательность вызовов java.util.concurrent.ConcurrentHashMap может не быть атомарной», когда я запускаю поиск ошибки в моем проекте для приведенного ниже кода.

public static final ConcurrentHashMap<String,Vector<Person>> personTypeMap = new ConcurrentHashMap<String, Vector<Person>>();

    private static void setDefaultPersonGroup() {


        PersonDao crud = PersonDao.getInstance();
        List<Person> personDBList = crud.retrieveAll();
        for (Person person : personDBList) {
            Vector<Person> personTypeCollection = personTypeMap.get(person
                    .getGroupId());
            if (personTypeCollection == null) {
                personTypeCollection = new Vector<Person>();
                personTypeMap.put(personTypeCollection.getGroupId(),
                        personTypeCollection);
            }
            personTypeCollection.add(person);
        }
    }

Я столкнулся с проблемой в строке personTypeMap.put(personTypeCollection.getGroupId(), personTypeCollection);

Может ли кто-нибудь помочь мне решить проблему.


person Murali    schedule 21.01.2014    source источник


Ответы (3)


Составные операции небезопасны в параллельной среде.

Какие сложные операции вы выполняете?

  • 1) Вы проверяете, содержит ли Map вектор для ключа
  • 2) Вы ставите новый Vector, если значение не найдено

Итак, это двухэтапное действие, составное, поэтому оно небезопасно.

Почему они не безопасны?

Потому что они не атомарны. Подумайте о сценарии, в котором у вас есть два потока.

Рассмотрим этот график:

Thread 1 --- checks for == null -> true                                           puts a new Vector

Thread 2 ---                      checks for ==null -> true    puts a new Vector                        

Используйте метод putIfAbsent() для ConcurrentHashMap, который предоставляет атомарное решение того, что вы пытаетесь выполнить.

ConcurrentHashMap #putIfAbsent()

Использованная литература:

person Narendra Pathai    schedule 21.01.2014
comment
Привет, когда я использую putifabsent, тогда найдите ошибку, выдающую ошибку, например, возвращаемое значение putIfAbsent игнорируется, но personTypeCollection повторно используется в setDefaultPersonGroup() - person Murali; 21.01.2014
comment
putIfAbsent возвращает значение, которое может быть нулевым, если ключ не был сопоставлен ни с чем, или с предыдущим значением для этого ключа. Поэтому вы должны использовать возвращаемое значение. - person Narendra Pathai; 21.01.2014
comment
Добро пожаловать. Вы также можете увидеть ответ @Bohemian в stackoverflow.com/questions/10743622/ - person Narendra Pathai; 21.01.2014

Это сообщение findbugs говорит вам, что в случае многопоточного доступа это небезопасно:

Вы получаете что-то из personTypeMap, проверяете, не является ли это null, а затем вставляете новую запись, если это так. Здесь могут легко чередоваться два потока:

Thread1: получить из карты
Thread2: получить из карты
Thread1: проверить возвращаемое значение на null
Thread1: ввести новое значение
Thread2: проверить возвращаемое значение на null
Thread2: ввести новое значение< бр>

(Просто в качестве примера; на самом деле порядок не задан - дело в том, что оба потока получают null, а затем действуют на него)

Вы должны создать новую запись, а затем вызвать personTypeMap.putIfAbsent(), так как это гарантирует атомарность.

person Brian Roach    schedule 21.01.2014
comment
Привет, когда я использую putifabsent(), тогда нахожу ошибку, выдающую ошибку, например, возвращаемое значение putIfAbsent игнорируется, но personTypeCollection повторно используется в setDefaultPersonGroup() - person Murali; 21.01.2014

В вашем случае ваш код должен выглядеть так:

public static final ConcurrentHashMap<String,Vector<Person>> personTypeMap = new ConcurrentHashMap<String, Vector<Person>>();

private static void setDefaultPersonGroup() {
    PersonDao crud = PersonDao.getInstance();
    List<Person> personDBList = crud.retrieveAll();
    for (Person person : personDBList) {
        // the putIfAbsent works in the same way of your
        //previous code, but in atomic way
        Vector<Person> personTypeCollection = personTypeMap.putIfAbsent(person
                .getGroupId());
        personTypeCollection.add(person);
    }
}
person Nilo Garcia Silveira    schedule 03.04.2017