Java 双重检查锁定的特殊情况?
我有一段代码,其中lockMap是一个Java 双重检查锁定的特殊情况?,java,multithreading,double-checked-locking,Java,Multithreading,Double Checked Locking,我有一段代码,其中lockMap是一个ConcurrentHashMap //Creation of locks Lock getLock(String key) { Lock lock = lockMap.get(key); if (lock == null) { synchronized (lockMap) { lock = lockMap.get(key); if (lock == null) {
ConcurrentHashMap
//Creation of locks
Lock getLock(String key) {
Lock lock = lockMap.get(key);
if (lock == null) {
synchronized (lockMap) {
lock = lockMap.get(key);
if (lock == null) {
lock = new ReentrantLock();
lockMap.put(key, lock);
}
}
}
return lock;
}
在代码审查期间,有人提到这是DCL的典型情况,因为编译器可以对事件重新排序,因此在插入映射时锁可能尚未完全初始化,那么请求相同锁的下一个线程可能尚未完全初始化
现在,我遇到的问题是,这个问题是多线程应用程序的一个常见问题:从映射中获取一些东西,如果没有,则创建并添加
ConcurrentHashMap中有锁的事实是。。。。令人困惑,但是,假设你知道你在用它们做什么,写这篇文章的更好方法是:
Lock getLock(String key) {
Lock lock = lockMap.get(key);
if (lock == null) {
lock = new ReentrantLock();
Lock race = lockMap.putIfAbsent(key, lock);
if (race != null) {
//there was a race, we lost.
lock = race;
}
}
return lock;
}
注意原子操作的使用。我们也乐观地创建了一个新的锁,但是如果我们失去了比赛条件,我们就会扔掉它,并使用比赛赢家锁。因此,不知何故,我没有收到任何通知,因此很抱歉响应太晚。 我想到了put if缺席,然而,总是免费创建一个对象是有成本的(大部分时间),所以我想避免这种情况。
但是我想成本是最低的,所以我将使用这个解决方案。重新排序哪些事件?为什么要查询锁两次,为什么在字典中有锁?为了使整个操作有任何意义,应该首先获得一个不在字典中的锁,例如synchonized方法,然后在返回之前锁定锁。它是DCL,但是正如@rolfl所示,没有必要在
ConcurrentHashMap
上进行同步。另外,“它在java 8中是固定的”是什么意思?这与java.to-Vidstige的版本无关。映射操作是线程安全的。不是它周围的东西。使用相同密钥的2个线程将获得null。两者都创建锁,都在映射中安全地插入值,但在外部使用两个不同的锁,这是错误的。不会编译,因为没有返回任何内容