2016-03-11 35 views
0

我有一张地图(我们称之为原始地图),它最初为空。在部署服务期间以及之后的每隔一小时,我需要刷新此映射或基本上对其进行处理。更新不可修改地图线程的引用安全

这是我该怎么做。在刷新过程中,我创建了一个新的地图,并将该新地图的一个不可修改的地图视图返回到了我的原始地图,而现在这个重新分配发生了,那就是原始地图的引用发生了变化,它是否会影响当前访问原始地图?需要注意的是,在服务部署期间,原始地图以类似的方式被赋值,基本上使用相同的刷新策略。

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

回答

2

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

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

实施例:

假定以下操作:

  • 变量“地图”包含对映射甲
  • T1参考通过“地图”,并存储,在某些局部变量引用检索地图甲,我们称之为“t1Map”
  • T2现在将“地图”更改为参照地图B
  • T1通过仍然参考A的“t1Map”访问地图A
  • T1通过“地图”,再次检索图A和现在得到参考到B
+0

所以我们只是需要确认在java中这个任务操作是否是原子或没有?事实上,这是我主要关心的是,重新分配会影响任何当前的线程。 –

+0

@ArnavSengupta看看我链接的线程。它说分配是原子的 - 我必须在JLS中查找相应的部分。 – Thomas

+0

只需添加,线程不会将其存储在局部变量中,它们全都从此公共映射中读取,TransactionData.plInfoByName。 –