更新unmodifiableMap线程的引用是安全的

时间:2016-03-11 16:07:37

标签: java hashmap thread-safety maps unmodifiable

我有一张地图(让我们称之为原始地图),该地图最初为空。在服务部署期间以及之后的每个小时,我需要刷新此映射或基本上重新放置它。

我是这样做的。在刷新时,我创建了一个新的地图,并将该新地图的不可修改的Map视图返回到我的原始地图,现在当这个重新分配发生时,原始地图的参考被更改,它是否会影响当前访问该地图的任何其他线程原图?需要注意的是,在服务部署期间,原始地图以类似的方式分配了一个值,基本上使用相同的刷新策略。

        private static Map<String, PricingPriceList> plInfoByName;
        TransactionData.plInfoByName = plInfo.get(0);

这里plInfoByName是我的原始地图,plInfo包含一个不可修改的地图列表。以下是填充plInfo列表的方法

    Map<String, PricingPriceList> plInfoByName = new HashMap<String, PricingPriceList>();
    Map<String, PricingPriceList> plInfoById = new HashMap<String, PricingPriceList>();

    try {
        stmt = dbConn.createStatement();
        stmt.setFetchSize(10000);

        rs = stmt.executeQuery(query);
        PricingPriceList plDetails = null;
        while (rs.next()) {
            plDetails = new PricingPriceList();

            //populate plDetails attributes

            plInfoByName.put(rs.getString(0), plDetails);
            plInfoById.put(rs.getString(1), plDetails);
        }

    } catch (Exception e) {
        LOGGER.ERROR("Error executing refreshPlInfo. Affected in-memory objects: plInfoByName, plInfoById.", e);
    } finally {
        try {
            if (stmt != null && !stmt.isClosed()) {
                stmt.close();
            }
            if (rs != null && !rs.isClosed()) {
                rs.close();
            }
        } catch (SQLException e) {
            LOGGER.ERROR("refreshPlInfo failed to close SQL statement or resultset.", e);
        }

    }

    // Return unmodifiable version
    List<Map<String, PricingPriceList>> plInfo = new ArrayList<Map<String, PricingPriceList>>();
    plInfo.add(Collections.unmodifiableMap(plInfoByName));
    plInfo.add(Collections.unmodifiableMap(plInfoById));
    return plInfo;

所以当我这样做时,它会影响任何读取TransactionData.plInfoByName的线程吗?或者它是否是线程安全的,因为它是存储在其中的unModifiableMap。

    TransactionData.plInfoByName = plInfo.get(0);

1 个答案:

答案 0 :(得分:2)

unmodifiableMap本身并不是线程安全的,它只是阻止用户更改它。在当前线程正在读取时,另一个可以访问底层映射的线程仍然可以更改它。

但是,如果您只是更改对地图的引用,则不应该影响当前正在访问&#34; old&#34;地图。假设(我必须检查一下)获取对象的引用是一个或多或少的原子操作(参见这里:What operations in Java are considered atomic?),任何引用了&#34; old& #34; map应该保留它,直到它再次检索引用。

示例:

假设以下操作:

  • 变量&#34; map&#34;包含对地图A
  • 的引用
  • T1检索地图A到&#34;地图&#34;以及在某个局部变量中引用的商店,让我们调用它&#34; t1Map&#34;
  • T2改变&#34; map&#34;现在推荐地图B
  • T1通过&#34; t1Map&#34;访问地图仍然引用A
  • T1检索地图A到&#34;地图&#34;再次,现在将获得对B
  • 的引用