【发布时间】:2021-10-01 06:27:27
【问题描述】:
我有一段代码在启动时创建了一个 ReentrantLock 键的 HashMap。
void constructor() {
this.lockMap = new HashMap<>();
for (int i=0; i<100; i++) {
this.lockMap.put(i, new ReentrantLock(true));
}
}
在并发执行期间,我尝试通过以下方式锁定lockMap内部的锁:
runConcurrently() {
ii = 10;
if (!lockMap.containsKey(ii)) {
log.error("lock id is not found in the lockMap " + ii);
}
locked = lockMap.get(ii).tryLock();
if (!locked) {
return;
}
runCriticialSection();
lockMap.get(ii).unlock();
}
void runCriticialSection() {
log.info("hello");
log.info("I'm here");
}
所以这是我在代码运行时每 4 小时看到一次的情况,这种情况非常罕见。
我看到了这些日志:
你好。
你好。
我在这。
我在这。
然后我在第三次访问同一键 ii =10 上的 hasmap 后立即看到此日志:
在地图 10 中找不到锁 ID。
NullPointerException ... 试图访问地图。
我应该在保证订购中看到的位置:
你好。
我在这。
你好。
我在这。
Hashmap 在执行期间根本不会被修改。
hashmap不是并发hashmap有问题吗?是获取,而不是在没有修改的情况下线程安全?由于并发hasmap的锁定速度很慢,我特别不使用它。但是 hashmap 只在启动时创建,之后永远不会修改。我觉得这很奇怪,似乎锁已被获取了两次,而且地图中似乎缺少该元素。
【问题讨论】:
-
您需要在记录未找到错误后从第一个 if 语句返回。这应该是 NullPointerException 的原因。我没有看到你在任何地方释放锁,但我认为你这样做了?另外,您检查 ii,然后使用 lockId。请发布您的实际代码,这不是完整的故事吗?
-
抱歉,我添加了其余代码。我添加了日志记录以确保密钥始终在地图中,因为地图从未被修改过。 NPE 永远不应该发生。
-
您应该在构造函数中初始化地图,而不是在方法
void constructor()中。我们不知道何时以及多久调用此方法。此外,runConcurrently()中没有变量声明。这意味着要么您在此处使用字段,受竞争条件的影响,要么您发布了虚构的伪代码而不是实际代码。似乎是后者,因为返回类型也丢失了,您已经不得不在稍后提交代码的关键部分。因此,我投票结束,因为我们无法在不查看代码的情况下告诉您代码有什么问题。
标签: java concurrency