这个代码线程是否安全,是否有更好的方法来实现它?

时间:2016-03-09 02:36:06

标签: java multithreading

我有以下代码:

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方法。上面的代码是否是线程安全的?我可以使用更好的数据结构,例如CopyOnWriteArrayListConcurrentHashMap吗?

理想情况下,我想摆脱同步块,但我不确定它是否可行。

2 个答案:

答案 0 :(得分:0)

这里的问题是Java中的并发类不会锁定自己来实现线程安全性。因此,您不能在代码中的某个位置依赖synchronized来与该对象的其余访问权限进行同步。

引用ConcurrentHashMap的Java文档:

  

但是,即使所有操作都是线程安全的,检索操作也不需要锁定,并且不支持以阻止所有访问的方式锁定整个表。在依赖于线程安全但不依赖于其同步细节的程序中,此类可与Hashtable完全互操作。

CopyOnWriteArrayList的Java文档没有指定其锁定特性,但由于它是写时复制,我怀疑它是否在内部锁定。当然,我不会指望它在生产代码中。

答案 1 :(得分:0)

您的toggleId()是线程安全的隔离

我的意思是,如果奇数个线程同时为同一个toggleId(i)调用i,那么最终结果将是iisInactive()切换,如果偶数号码同时调用它,那么最终结果将是无操作。

但它与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 方法。