1

我知道您必须围绕任何会改变哈希图结构(放置或删除)的东西进行同步,但在我看来,您还必须围绕哈希图的读取同步,否则您可能正在阅读,而另一个线程正在改变结构哈希图。

所以我同步gets和puts到我的hashmap。我可以用来测试的唯一机器只有一个处理器,所以在系统投入生产并开始出现故障之前,我从来没有任何真正的并发。我的哈希图中缺少项目。我认为这是因为两个线程同时写入,但根据下面的代码,这应该是不可能的。当我将线程数减少到 1 时,它开始完美地工作,所以这绝对是一个线程问题。

细节:

// something for all the threads to sync on
private static Object EMREPORTONE = new Object();


    synchronized (EMREPORTONE)
      {
        reportdatacache.put("name.." + eri.recip_map_id, eri.name);
        reportdatacache.put("subjec" + eri.recip_map_id, eri.subject);
        etc...
      }

……和其他地方……

    synchronized (EMREPORTONE)
      {
        eri.name = (String)reportdatacache.get("name.." + eri.recip_map_id);
        eri.subject = (String)reportdatacache.get("subjec" + eri.recip_map_id);
        etc...
      }

就是这样。我在函数之间传递reportdatacache,但这只是对哈希图的引用。

另一个重要的一点是,它在应用服务器中作为 servlet 运行(具体来说是 iplanet,但我知道你们中没有人听说过)

但无论如何,EMREPORTONE 对于网络服务器进程来说是全局的,没有两个线程应该能够互相踩踏,但我的 hashmap 却被破坏了。有什么想法吗?

4

3 回答 3

1

是的,同步不仅在写作时很重要,在阅读时也很重要。虽然将在互斥情况下执行写入,但读取器可能会访问映射的错误状态。

不建议您在任何情况下手动同步Java 集合,有线程安全的对应项:Collections.synchronizedMapConcurrentHashMap。使用它们,他们将确保在多线程环境中访问它们是安全的。

进一步提示,似乎每个人都在访问datareportcache. 该对象只有一个实例吗?为什么不在缓存本身上同步呢?但是在尝试解决问题时忘记使用java.util.concurrent 中的糖。

于 2012-07-05T18:28:47.770 回答
1

在 servlet 容器环境中,静态变量依赖于类加载器。所以你可能认为你正在处理相同的静态实例,但实际上它可能是完全不同的一个。

此外,检查您是否不通过其他地方的转义引用使用地图并从中写入/删除键。

是的,请改用 ConcurrentHashMap 。

于 2012-07-05T18:32:40.940 回答
1

在我看来,这里有 3 种可能性:

  1. 您正在锁定两个不同的对象。 但是,访问 的代码EMREPORTONE仅在一个文件中。好吧,那不是。但我建议锁定而不是。更干净的代码。private staticreportdatacachereportdatacacheEMREPORTONE

  2. 你错过了一些读或写的reportdatacache地方。还有其他对地图的访问不是synchronized. 东西永远不会从缓存中删除吗?

  3. 这不是同步问题,而是竞争条件问题。hashmap 中的数据很好,但是您希望缓存中的数据,但它们还没有被其他线程存储。也许 2 个请求同时eri进入,并且它们都将值放入缓存中?也许检查返回的旧值put(...)是否始终为空?也许解释更多关于您如何知道地图中缺少项目的信息将对此有所帮助。

顺便说一句,您正在这样做:

reportdatacache.put("name.." + eri.recip_map_id, eri.name);
reportdatacache.put("subjec" + eri.recip_map_id, eri.subject);

但看起来你真的应该eri通过它的 id 来存储它。

reportdatacache.put(recip_map_id, eri);

那么您就不会使用"name.."前缀创建假密钥。或者,也许您应该创建一个NameSubject private static class将名称和主题存储在缓存中。清洁器。

希望这里有帮助。

于 2012-07-05T20:26:57.623 回答