【问题标题】:why java.util.HashMap.getEntry can block my program?为什么 java.util.HashMap.getEntry 可以阻止我的程序?
【发布时间】:2011-03-26 15:47:30
【问题描述】:

我的程序被阻塞了,我用jstack命令分析,后面的线程拿了锁“0x0000000603f02ae0”,其他线程拿不到锁。
我已经等了至少一个小时,但是线程没有解锁,我的问题是为什么线程的状态是 RUNNING,并停在 java.util.HashMap.getEntry(HashMap.java:347) ?是oracle(sun) JDK的bug?

我的 jdk 版本:
java版本“1.6.0_21”
Java(TM) SE 运行时环境(内部版本 1.6.0_21-b06)
Java HotSpot(TM) 64 位服务器 VM(内部版本 17.0-b16,混合模式)

线程信息:
“PandoraScheduleTrigger-thread-5”prio=10 tid=0x00000000443b0800 nid=0x5804 可运行 [0x0000000043722000] java.lang.Thread.State:可运行 在 java.util.HashMap.getEntry(HashMap.java:347) 在 java.util.HashMap.containsKey(HashMap.java:335) at com.youlongqingfeng.pandora.context.ArmiesContext._getArmy(ArmiesContext.java:239) at com.youlongqingfeng.pandora.context.ArmiesContext.getArmiesByCityId(ArmiesContext.java:169) at com.youlongqingfeng.pandora.model.City.getTotalApplianceMap(City.java:4519) at com.youlongqingfeng.pandora.model.City.calculateMemoryResource(City.java:4636) at com.youlongqingfeng.pandora.model.City.buildTaskFinish(City.java:1089) at com.youlongqingfeng.pandora.map.unit.ZhouMapResourceUnit.buildTaskFinish(ZhouMapResourceUnit.java:1618) - 锁定(com.youlongqingfeng.pandora.map.unit.ZhouMapResourceUnit) 在 com.youlongqingfeng.pandora.trigger.BuildTrigger.innerRun(BuildTrigger.java:39) 在com.youlongqingfeng.gameserver.utils.threadpool.CancelTrigger.run(CancelTrigger.java:34)

阻塞的线程转储:

“PandoraScheduleTrigger-thread-3”prio=10 tid=0x0000000044c7c000 nid=0x5802 等待监视器条目 [0x0000000043520000] java.lang.Thread.State: BLOCKED(在对象监视器上) at com.youlongqingfeng.pandora.map.unit.ZhouMapResourceUnit.armiesGroupReturnBack(ZhouMapResourceUnit.java:2279) - 等待锁定(一个com.youlongqingfeng.pandora.map.unit.ZhouMapResourceUnit) at com.youlongqingfeng.pandora.trigger.ArmyGroupArrivedTrigger.innerRun(ArmyGroupArrivedTrigger.java:53) 在 com.youlongqingfeng.gameserver.utils.threadpool.CancelTrigger.run(CancelTrigger.java:34) 在 java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441) 在 java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) 在 java.util.concurrent.FutureTask.run(FutureTask.java:138) 在 java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:98) 在 java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:207) 在 java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) 在 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) 在 java.lang.Thread.run(Thread.java:619)

谢谢。

【问题讨论】:

标签: multithreading thread-safety java threadpool


【解决方案1】:

实际上,您可以使用 ConcurrentHashMap 代替 HashMap。 当不同的线程循环访问映射时,HashMap 会进入阻塞状态。可以有效地使用 ConcurrentHashMap。它是同步且高效的。它不会锁定整个 Map,它只是锁定当前访问的存储桶。

【讨论】:

    【解决方案2】:

    如果有多个线程,使用Hashtable,如果只有一个线程,使用HashMap。

    【讨论】:

    • Hashtable很慢,我用readWriteLock解决了,谢谢。
    【解决方案3】:

    你确定线程在 getEntry 处停止吗?状态是 runnable,所以我想它是 run 吗?在这一步你用 jstack 赶上,就是这样。我想ZhouMapResourceUnit.buildTaskFinish下面有一种无限循环,锁永远不会被释放。

    【讨论】:

      【解决方案4】:

      需要考虑的一些事项:

      • 您正在使用HashMap,它本身并没有同步。您是否在所有访问点同步访问代码中的地图?如果您不这样做,则对地图的并发访问可能会损坏内部数据,从而导致不可预测的行为。

      • 一个线程有一个锁,另一个正在尝试获取它。您是否有可能遇到涉及 2 个锁的情况,其中 2 个线程正在等待另一个线程在释放他们锁定的锁之前释放他们需要的锁? (线程 1 锁定 a,等待 b + 线程 2 锁定 b 等待 a -> 死锁。)

      【讨论】:

      • 谢谢,我得到了答案,因为线程得到了ReadLock,但是我在map中写了一些数据,所以出现了这个bug。
      • 我在mybatis中发现了同样的bug~getEntry只是永远循环。好伤心
      • @PeterLee 嘿,我在 PROD 中有一个非常相似的情况,在多线程进程中访问了一个 HashMap,其中所有 5 个线程都被锁定 at java.util.HashMap.getEntry(HashMap.java:480)。我想了解您关于 ReadLock 的声明。您的意思是在读取元素时您只是 HashMap 中的puting 元素吗?或者您在ReadWriteLock.readLock() 的代码中实现了从地图中获取项目,而puting 元素没有做任何事情?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-06-19
      • 2015-03-08
      • 1970-01-01
      • 2018-04-19
      • 1970-01-01
      • 1970-01-01
      • 2014-06-25
      相关资源
      最近更新 更多