简体   繁体   中英

Concurrent Map with one key and multiple values

I need to have a Map which is thread safe and can have multiple values. I did write one using MultiMap as

    private MultiMap<String, String> uploadIdETagMap = new MultiValueMap<String, String>();

//Function to get tag value and add to map to that uploadId key
    public void uploadPartForMultiPartUpload() {
        try {
            UploadPartRequest partRequest = new UploadPartRequest();
            partRequest = partRequest.withBucketName(bucketName).withInputStream(inputStream).withKey(fileName)
                    .withPartNumber(partNumber).withUploadId(uploadId).withPartSize(sizeOfData)
                    .withLastPart(isLastPart);
            UploadPartResult result = s3Client.uploadPart(partRequest);
            uploadIdETagMap.put(uploadId, result.getPartETag());
        } catch (Exception e) {
            log.error("Error uploading part: {} in multi part upload.", partNumber, e);
        }
    }

    List<String> tagList = (List<String>) uploadIdETagMap.get(uploadId);

So everytime i will get new tag value for a particular uplaodId key and i need all of those tags at the end and there will be other uploads processing same time.

In the above code, tag gets added every time as the value of the MultiMap for specific uploadId key. The above code works, but both MultiMap and MultiValueMap is deprecated and not thread safe.

So any suggestion how can i achieve this with latest version and thread safety.

tl;dr

personFavoriteColors.computeIfAbsent( 
    "Alice" , 
    ( x -> new CopyOnWriteArrayList<>() )
)
.add( "Purple" )
;

personFavoriteColors.computeIfAbsent( 
    "Alice" , 
    ( x -> new CopyOnWriteArrayList<>() )
)
.add( "Gold" )
;

personFavoriteColors.toString(): [Purple, Gold]

Map::computeIfAbsent

Java now has multimap behavior built-in with new computeIfAbsent method defined on the Map interface.

Define your map.

ConcurrentMap< String , Set< String> > personFavoriteColors = new ConcurrentSkipListMap<>() ;

We are using a Map implementation that implements the ConcurrentMap interface for thread-safety as you requested. Java offers two such implementations.

Java 11 中的地图实现表,比较它们的特性

Use a single line to create a new list or set to hold the multiple values.

personFavoriteColors.computeIfAbsent( 
    "Alice" , 
    ( x -> new CopyOnWriteArraySet<>() )   // Lambda expression. Run only if needed to run (if absent). 
)                                          // Returns the value of a map (a `Set` or `List` when desiring a multimap). 
.add( "Purple" )
;

You may access the Set (or List ) outside of the Map that owns it. So that Set (or List ) must also be concurrent.

Here we used a concurrent set, CopyOnWriteArraySet as our value for the map.

For example:

Set< String > favoriteColorsForAlice = personFavoriteColors.get( "Alice" ) ;
System.out.println( favoriteColorsForAlice ) ; 

See this code run live on IdeOne.com .

[Purple, Gold]

For whatever Map<String,List<String>> implementation you use you could do the following:

String key;
String value;
map.compute(key, ((k,v)-> v == null ? new ArrayList<>() : v).add(value));

The above checks to see if the List<String> for key exists, if not it creates one, otherwise, it uses the existing one. In both cases, the value is added to the new or existing list for a given key.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM