更新 unmodifiableMap 线程安全的引用
Is updating reference of unmodifiableMap thread safe
我有一张地图(我们称之为原始地图),它最初是空的。在服务部署期间以及之后的每个小时,我都需要刷新这张地图或者基本上重新评估它。
这是我的做法。在刷新中,我创建了一个新地图,并且 return 那个新地图的 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);
unmodifiableMap
本身不是线程安全的,它只是防止用户更改它。另一个有权访问底层地图的线程仍然可以在当前线程读取时更改它。
但是,如果您只是更改对地图的引用,它应该不会影响当前正在访问 "old" 地图的任何线程。假设(我必须检查)获取对对象的引用或多或少是一个原子操作(参见此处:What operations in Java are considered atomic?),任何获得对 "old" 映射的引用的线程都应该保留它直到它再次检索引用。
示例:
假设以下操作:
- 变量 "map" 包含对地图 A 的引用
- T1 通过 "map" 检索映射 A 并将该引用存储在某个局部变量中,让我们调用它 "t1Map"
- T2现在"map"改为参考图B
- T1 通过 "t1Map" 访问映射,它仍然引用 A
- T1 再次通过 "map" 检索映射 A,现在将获得对 B
的引用
我有一张地图(我们称之为原始地图),它最初是空的。在服务部署期间以及之后的每个小时,我都需要刷新这张地图或者基本上重新评估它。
这是我的做法。在刷新中,我创建了一个新地图,并且 return 那个新地图的 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);
unmodifiableMap
本身不是线程安全的,它只是防止用户更改它。另一个有权访问底层地图的线程仍然可以在当前线程读取时更改它。
但是,如果您只是更改对地图的引用,它应该不会影响当前正在访问 "old" 地图的任何线程。假设(我必须检查)获取对对象的引用或多或少是一个原子操作(参见此处:What operations in Java are considered atomic?),任何获得对 "old" 映射的引用的线程都应该保留它直到它再次检索引用。
示例:
假设以下操作:
- 变量 "map" 包含对地图 A 的引用
- T1 通过 "map" 检索映射 A 并将该引用存储在某个局部变量中,让我们调用它 "t1Map"
- T2现在"map"改为参考图B
- T1 通过 "t1Map" 访问映射,它仍然引用 A
- T1 再次通过 "map" 检索映射 A,现在将获得对 B 的引用