Поведение ConcurrentHashMap и вопросы

У меня есть 4 потока - 2 потока обновляются, а 2 потока читаются на concurrentHashMap. Код выглядит следующим образом:

private static ConcurrentHashMap<String, String> myHashMap = new ConcurrentHashMap<>();
private static final Object lock = new Object();

Метод запуска потока 1 и потока 2 (ключ и значение представляют собой строку)

synchronized (lock) {
    if (!myHashMap.containsKey(key)) {
        myHashMap.put(key, value);
    } else {
        String value = myHashMap.get(key)
        // do something with the value
        myHashMap.put(key, value);
    }
}

Метод запуска Thread 3 и Thread 4 выполняет печать

for (Entry<String, String> entry : myHashMap.entrySet()) {
    String key = entry.getKey();
    String value = entry.getValue();
    System.out.println("key, " + key + " value " + value);
}

Есть ли проблема с приведенным выше использованием кода ConcurrenHashMap? Потому что, когда я читал Javadoc и искал в Интернете, я нашел следующее утверждение:

  1. Этот класс полностью совместим с Hashtable в программах, которые полагаются на его потокобезопасность, но не на детали синхронизации. (Примечание. Я понимаю, что результат потока печати может быть не самым последним результатом, но это нормально. пока поток обновления делает все правильно.)
  2. Существует также некоторая претензия к веб-сайту, в которой говорится, что один и тот же итератор нельзя использовать для двух или более разных потоков. Поэтому мне интересно, использует ли метод печати тот же итератор в двух потоках выше. И почему мы не можем использовать один и тот же итератор в двух разных потоках?

Что касается требования, я хочу одновременное чтение без блокировки, поэтому я выбираю ConcurrentHashMap.


person Harry Wang    schedule 17.07.2018    source источник
comment
Есть ли проблема с приведенным выше кодом? Я не думаю, что мы можем ответить на этот вопрос, не зная точно, что вы хотите сделать и как вы это делаете. Ваш фрагмент кода слишком расплывчатый. Инструкции по созданию лучшего примера кода см. на stackoverflow.com/help/mcve.   -  person Radiodef    schedule 17.07.2018
comment
Обновил код. Сделать что-то со значением означает просто вычислить значение.   -  person Harry Wang    schedule 17.07.2018
comment
@Nathan Hughes Ну, мне нужно убедиться, что поток обновлений заблокирован, поэтому только 1 поток может выполнить обновление, другой должен ждать.   -  person Harry Wang    schedule 17.07.2018
comment
Вам просто нужно предположить, что поток обновления может быть запущен только атомарно для всего кода внутри.   -  person Harry Wang    schedule 17.07.2018
comment
Вы подрываете всю цель CHM, используя его под внешним замком. Вместо этого используйте атомарное merge().   -  person shmosel    schedule 17.07.2018
comment
Я не думаю, что мы действительно можем предложить compute или merge, не зная, что на самом деле делает что-то со значением.   -  person Radiodef    schedule 17.07.2018
comment
Помните, что вся цель использования CHM в этом случае состоит в том, чтобы добиться неблокирующего чтения/печати.   -  person Harry Wang    schedule 17.07.2018
comment
Недавно я наткнулся на ветку с похожим постом; может быть, это прояснит ваши сомнения: Java concurrent hashMap retrieval   -  person prasad_    schedule 17.07.2018


Ответы (1)


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

person Dinesh    schedule 17.07.2018
comment
Дело в том, что я не могу использовать сборку в методе putIfAbsent из-за сложности вычислений. И почему бы нам не использовать внешнюю блокировку? Есть ли неожиданное поведение при использовании внешней блокировки? или это только из-за производительности? Бьюсь об заклад, производительность не может быть хуже, чем при использовании Hashtable, который блокируется даже в потоке чтения. - person Harry Wang; 17.07.2018