0

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

这是我的做法。在刷新中,我创建了一个新地图,并将该新地图的 unmodifiableMap 视图返回到我的原始地图,现在当重新分配发生时,即原始地图的引用发生更改,它会影响当前访问的任何其他线程原始地图?需要注意的是,在服务部署过程中,原始地图以类似的方式赋值,使用的刷新策略基本相同。

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

1 回答 1

2

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

但是,如果您只是更改对地图的引用,它不会影响当前正在访问“旧”地图的任何线程。假设(我必须检查)获取对对象的引用或多或少是原子操作(请参阅此处:Java 中的哪些操作被认为是原子的?),任何获取“旧”映射引用的线程应该保留它,直到它再次检索到引用。

例子:

假设以下操作:

  • 变量“map”包含对地图 A 的引用
  • T1 通过“map”检索地图 A 并将该引用存储在某个局部变量中,我们称之为“t1Map”
  • T2 现在将“地图”更改为参考地图 B
  • T1 通过仍然引用 A 的“t1Map”访问地图
  • T1 再次通过“map”检索地图 A,现在将获得对 B 的引用
于 2016-03-11T16:24:31.410 回答