我有以下代码:
public class MySystem {
private ConcurrentHashMap<Integer, Integer> disabledList = new ConcurrentHashMap<>();
public void toggle(int id) {
synchronized (disabledList) {
if (disabledList.containsKey(id)) {
disabledList.remove(id);
} else {
disabledList.put(id);
}
}
}
public boolean isInactive(int id) {
return disabledList.containsKey(id);
}
}
多个线程可能会调用toggleId
方法。上面的代码是否是线程安全的?我可以使用更好的数据结构,例如CopyOnWriteArrayList
或ConcurrentHashMap
吗?
理想情况下,我想摆脱同步块,但我不确定它是否可行。
答案 0 :(得分:0)
这里的问题是Java中的并发类不会锁定自己来实现线程安全性。因此,您不能在代码中的某个位置依赖synchronized
来与该对象的其余访问权限进行同步。
引用ConcurrentHashMap
的Java文档:
但是,即使所有操作都是线程安全的,检索操作也不需要锁定,并且不支持以阻止所有访问的方式锁定整个表。在依赖于线程安全但不依赖于其同步细节的程序中,此类可与Hashtable完全互操作。
CopyOnWriteArrayList
的Java文档没有指定其锁定特性,但由于它是写时复制,我怀疑它是否在内部锁定。当然,我不会指望它在生产代码中。
答案 1 :(得分:0)
您的toggleId()
是线程安全的隔离。
我的意思是,如果奇数个线程同时为同一个toggleId(i)
调用i
,那么最终结果将是i
是isInactive()
切换,如果偶数号码同时调用它,那么最终结果将是无操作。
但它与isInactive(i)
的关系呢?如果线程A调用toggleId(i)
,然后线程B在线程A能够对isInactive(i)
返回的值进行操作之前调用ConcurrentHashMap
,这意味着什么?
我想摆脱同步的阻止,但我不确定它是否可能。
总之,没有。只有当toggleId
为您实现类似线程安全的disabledList.putIfAbsent(...)
函数时才有可能,但我在其API中看不到任何适合的内容。 putIfAbsentOrDeleteIfPresent(...)
一半工作,但没有DECLARE @RC INT;
SET @RC = 1;
WHILE (@RC > 0)
BEGIN
BEGIN TRAN
DELETE FROM YOUR_TABLE
WHERE ID IN (
SELECT TOP(1000) ID
FROM YOUR_TABLE AS T
WHERE {your criteria for deletion using alias T}
);
SET @RC = @@ROWCOUNT;
COMMIT
END
方法。