Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Updating elements atomically retrieving from Map using Java 8 parallel streams

I have a parallel stream in which I'm using a Map to mutate the elements.

Map<Long, List<MyItem>> hashmap = foo.getMap();

itemStream.parallel()
  .filter(Objects::nonNull)
  .forEach(item -> setProperties(hashmap, item));

The method 'setProperties()' takes the map and item, and performs a get using item and then sets some attributes of the item.

What I want is for the getting/property setting to be done atomically. So that two threads can't perform a get on the same key and have property updates be interleaved.

private void setProperties(Map<Long, List<Item>> map, Item item) {
    long id = item.getID();
    List<Object1> items = map.get(id);
    for (Object1 ob : items) {
            ob.setId(item.getFloorId());
            ob.setPath(item.getPath());
            ob.setTypeName(item.getTypeName());
    }
}

Also a bit concerned about the latency hit and whether this sort of parallelization will really have a benefit vs the existing single threaded approach.

like image 849
SS' Avatar asked Mar 06 '23 18:03

SS'


1 Answers

Synchnorising the Map or the get from it has no benefit, because the map is not being altered so there’s no race condition.

You need to synchronise the updates so they happen all-at-once:

for (Object1 ob : items) {
    synchronized (ob) {
        ob.setId(item.getFloorId());
        ob.setPath(item.getPath());
        ob.setTypeName(item.getTypeName());
    }
}

This will have very little impact on performance, because these days synchronising introduces very little overhead and you will only block if the same Item is being operated on.

like image 102
Bohemian Avatar answered Mar 09 '23 01:03

Bohemian