【问题标题】:Concurrent Map with one key and multiple values一键多值的并发映射
【发布时间】:2023-03-29 05:36:02
【问题描述】:

我需要一个线程安全且可以有多个值的 Map。我确实使用MultiMap 写了一个

    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);

所以每次我都会为特定的 uplaodId 键获得新的标签值,最后我需要所有这些标签,并且同时会有其他上传处理。

在上面的代码中,每次都会添加tag 作为特定uploadId 键的MultiMap 的值。 上述代码有效,但MultiMapMultiValueMap 均已弃用且不是线程安全的。

所以任何建议我如何才能通过最新版本和线程安全来实现这一点。

【问题讨论】:

    标签: java collections hashmap thread-safety


    【解决方案1】:

    tl;博士

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

    personFavoriteColors.toString(): [紫、金]

    Map::computeIfAbsent

    Java 现在内置了 multimap 行为,并在 Map 接口上定义了新的 computeIfAbsent 方法。

    定义你的地图。

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

    我们正在使用Map 实现,它根据您的要求实现了ConcurrentMap 接口以实现线程安全。 Java 提供了两种这样的实现。

    使用单行创建一个新列表或设置以保存多个值。

    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" )
    ;
    

    您可以在拥有它的Map 之外访问Set(或List)。所以Set(或List)也必须是并发的。

    这里我们使用并发集 CopyOnWriteArraySet 作为地图的值。

    例如:

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

    看到这个code run live on IdeOne.com

    [紫、金]

    【讨论】:

    • 谢谢@Basil .. 它有效
    • 我很困惑,你的例子中为什么使用computeIfAbsent而不是putIfAbsent
    【解决方案2】:

    对于您使用的任何Map&lt;String,List&lt;String&gt;&gt; 实现,您都可以执行以下操作:

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

    上面检查List&lt;String&gt; for key是否存在,如果不存在,则创建一个,否则使用现有的。在这两种情况下,都会将值添加到给定键的新列表或现有列表中。

    【讨论】:

    • 实际上,我不会预先列出列表,根据键值应该与现有的键值相加。假设如果我有两个键并且从该函数返回的值将是一个字符串,那么在将第一个值添加到键之后,我应该能够将下一个值添加到同一个键或其中之一。我将无法创建值列表并添加,它应该是一个一个。
    • 所以对于重复的键,您正在以某种方式更改每个键以允许键到值的一对一映射?你能举个例子吗?
    • @ShivendraSharma 对不起,我不清楚我的意思。完成的地图是什么样子的。你可以只使用字符串。假设您有一个密钥“abcd”。那么是“abcd”,然后是“abcd1”和“abcd2”,其中 1,2,.. 是更改每个值的键的标签吗?还是每次出现具有相同键的值时,您只是将下一个字符串附加到现有值?
    • 所以,我有一个键“abcd”,另一个键是“efgh”,现在值将来自如上所示基于键的函数,现在假设在运行该函数一次后,我得到“ 1234”作为键“abcd”的值,我保存了它。再次获得键“abcd”的值为“4321”,需要将其添加为“abcd”的值,依此类推。介于两者之间的值也将用于“efgh”,因此应该能够以相同的方式工作。
    • 但是由于map不能有重复的key,所以通常有两种选择。一种是将它们放在一个列表中,或者如果它们是字符串,则可以将它们连接到现有字符串,用分隔符分隔,如逗号。根据您之前的陈述我不能预先列出清单。根据我的示例,该列表仅在您需要时创建。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-30
    • 2013-03-12
    • 2013-06-28
    • 2021-09-11
    • 2023-01-21
    相关资源
    最近更新 更多