我有一些代码使用ConcurrentHashMap
并想确认我正在做的事情是否正确。
映射将String存储为键,将集合(Set
)存储为值。我最初有一个实现,我会使用锁定条带模式以原子方式执行某些操作(put,remove等),但后来意识到我可以使用computeIfAbsent/putIfAbsent
(for put)和{{1} }(删除)。多个线程调用所有4个方法(get,put,removeKey,removeValue)。
有人能告诉我我的AFTER代码是否正确并且是线程安全的吗?提前谢谢!
computeIfAbsent
BEFORE
private final ConcurrentMap<K, Set<V>> map = new ConcurrentHashMap<>();
private final ConcurrentMap<K, Object> locks = new ConcurrentHashMap<>();
public Set<V> getValue(K key) {
if (map.get(key) == null) return null;
return map.get(key).stream().map(k -> k.getValue()).collect(Collectors.toSet());
}
AFTER
private void putValue(K key, V value) {
Object lock = locks.putIfAbsent(key, new Object());
if (lock == null) lock = locks.get(key);
Set<V> existingSet = map.computeIfAbsent(key, k -> {
Set<V> values = new ConcurrentSkipListSet<>(MY_COMPARATOR);
values.add(value);
return values;
});
if (existingSet != null) { // <- my guess is that this is unnecessary
synchronized (lock) {
map.get(key).add(expiringValue);
}
}
}
public void removeKey(K key) {
if (key == null) return;
if (map.get(key) != null) {
Object lock = locks.get(key);
synchronized (lock) {
map.remove(key);
}
locks.remove(key);
}
}
public void removeValue(K key, V value) {
if (key == null || value == null) return;
if (map.get(key) != null) {
Object lock = locks.get(key);
synchronized (lock) {
map.get(key).remove(value);
if (map.get(key).size() == 0) {
map.remove(key);
}
}
}
}
答案 0 :(得分:1)
至少有一个问题是您可能会使用putValue
丢失值。 computeIfAbsent
是线程安全的,但add()
已不再存在。因此,您可以(根据您的逻辑)提出以下方案:
T1: computeIfAbsent creates the set for key K
T2: removes K
T1: performs add on the set, which is no longer in the map
答案 1 :(得分:1)
我认为你能做的最稳定就是这样:
private void putValue(K key, V value) {
map.compute(key, (k, values) -> {
if (values == null) {
values = new ConcurrentSkipListSet<>(MY_COMPARATOR);
}
values.add(value);
return values;
});
}
public void removeKey(K key) {
map.remove(key); // No change.
}
public void removeValue(K key, V value) {
map.computeIfPresent(key, (k, values) -> {
values.remove(value);
return values.isEmpty() ? null : values;
});
}
这些保证所有行动都是原子的。 putValue
ConcurrentHashMap
在null
中的使用感觉有点笨拙,但null
保证了行为,所以无论如何。
在compute
中返回$("input[type=radio]").on('click', function() {
var secondClick = true;
$(this).change(function() {
secondClick = false;
});
$(this).click(function() {
if (secondClick) {
$(this).prop("checked", false);
}
secondClick = true;
});
});
的重新映射功能正是您正在尝试执行的操作的正确方法:
如果函数返回
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <form name="myForm" id="myForm" method="POST" action="#"> <div class="formItem"> <label for="evaluation">Evaluation</label> <input type="radio" name="frm_eval" id="frm_eval1" value="0" />Yes <input type="radio" name="frm_eval" id="frm_eval2" value="1" />No </div> <div class="formItem"> <label for="conditions">Conditions</label> <input type="radio" name="frm_cond" id="frm_cond1" value="0" />Good <input type="radio" name="frmhs_cond" id="frm_cond2" value="1" />Fair <input type="radio" name="frm_cond" id="frm_cond3" value="2" />Poor </div> <div class="formItem"> <label for="responses">Responses</label> <input type="radio" name="frm_res" id="frm_res1" value="0" />Good <input type="radio" name="frm_res" id="frm_res2" value="1" />Fair <input type="radio" name="frm_res" id="frm_res3" value="2" />Poor </div> </form>
,则删除映射。