Java потоки невмешательства и побочные эффекты - PullRequest
0 голосов
/ 22 октября 2018

Глядя на документацию по пакету Java java.util.stream, возникло сомнение в отношении лучших практик использования потоков.Учитывая этот код:

HashMap<Integer,Integer> map = new HashMap<>();
map.put(1,1);
map.put(2,2);
map.put(3,3);
map.put(4,4);
map.keySet().parallelStream().forEach(key -> {
        if (key == 3) { 
            map.put(3,0);
        }
});
  1. Всегда ли выход кода равен ([1,1], [2,2], [3,0], [4,4])?
  2. Может ли map.put (3,0) рассматриваться как не мешающая операция?
  3. Может ли map.put (3,0) рассматриваться как приемлемый побочный эффект?

Другими словами, приведенный выше код можно считать совместимым с лучшими практиками, предложенными в документации по потокам?

Ответы [ 3 ]

0 голосов
/ 22 октября 2018

Нет, нет, нет.
Избегать побочных эффектов.
Пример кода, соответствующий документации:

Map<Integer,Integer> updatedMap = map.keySet().parallelStream()
        .filter(e -> e == 3)
        .collect(Collectors.toMap(Function.identity(), e -> 0));
map.putAll(updatedMap);
0 голосов
/ 22 октября 2018

Сравнить (а)

map.keySet().parallelStream().forEach(key -> {
        if (key == 3) { 
            map.put(3, 0);
        }
});

(добавлена ​​новая запись)

с (б)

map.entrySet().parallelStream().forEach(e -> {
        if (e.getKey() == 3) { 
            e.setValue(0);
        }
});

(объект Entry не создан, перемещен. Но остерегайтесь LinkedHashMap.)

  • (a) Небезопасный
  • (b) Безопасный

    1. Всегда ли выход кода равен ([1,1], [2,2], [3,0], [4,4])?

      (a)нет (б) да

    2. Может ли map.put(3, 0) рассматриваться как не мешающая операция?

      (а) нет (б) setValue(0) да

    3. Можно ли считать map.put(3, 0) приемлемым побочным эффектом?

      (a) нет (b) setValue(0) да

Так (а) это зло и (б) все в порядке.

Почему упоминание entrySet.setValue?

На самом деле HashMap.putв реализации Oracle 1056 *, вероятно, делает то же самое, что и Entry.setValue.Это потребует использования знаний о реализации - безобразно.

Принимая во внимание, что Entry.setValue основан на поддержке исходной карты, и можно заключить, что только поле значения перезаписывается.Обратите внимание, что LinkedHashMap необходимо изменить порядок записи, и это изменение порядка снова небезопасно.

0 голосов
/ 22 октября 2018

Ваш пример определенно нарушает требование о невмешательстве :

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

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

Поэтому ответ на ваши 2-й и 3-й вопросы - нет.

Что касается первого вопроса, ваш конкретный код все еще может произвестиожидаемый результат, поскольку ваше условие гарантирует, что только один поток вызовет map.put(3,0).Тем не менее, это все еще считается неправильным использованием Stream s.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...