JDK 提供的并发类是否需要使用其实例自己的内部锁进行同步?



JDK提供了一组线程安全类,如ConcurrentHashMap,ConcurrentLinkedQueue和AtomicInteger。

是否需要这些类在this上同步以实现其线程安全行为?

只要他们这样做,我们可以在这些对象上实现我们自己的同步操作并将它们与内置对象混合?

换句话说,这样做是否安全:

ConcurrentMap<Integer, Account> accounts 
    = new ConcurrentHashMap<Integer, Account>();

// Add an account atomically
synchronized(accounts) {
    if (!accounts.containsKey(id)) {
        Account account = new Account();
        accounts.put(id, account);
    }
}

在另一个线程中

// Access the object expecting it to synchronize(this){…} internally
accounts.get(id);

请注意,上面的简单同步块可能会被 putIfAbsent() 替换,但我可以看到在对象上进行同步可能有用的其他情况。

这些类是否需要 在此同步以实现其 线程安全行为。

不,不仅如此,如果您尝试使用对象锁,各种代码检查工具会警告您。

在上面的 put 方法的情况下,请注意 javadoc:

支持完整 检索的并发性和 可调整的预期并发性 更新。这个类服从相同的 功能规范作为哈希表, 并包括方法的版本 对应每种方法 哈希表。然而,即使所有 操作是线程安全的,检索 操作不需要锁定,并且 没有任何锁定支持 整个表,以 阻止所有访问。此类是 与哈希表完全可互操作 依赖于其线程的程序 安全但不同步 详。

这意味着这些选项是线程安全的,并且没有办法执行您尝试在上面执行的操作(锁定整个表)。 此外,对于您使用的操作(放置和获取),它们都不需要此类锁定。

我特别喜欢 values() 方法中 javadoc 的这句话:

视图的迭代器是"弱 一致"的迭代器,永远不会 抛出并发修改异常, 并保证遍历元素 它们存在于建造 迭代器,并且可能(但不是 保证)反映任何 之后的修改 建设。

因此,如果您使用此方法,您将获得一个合理的列表:它将具有截至请求时间的数据,并且可能会也可能不会有任何后续更新。 您不必担心 ConcurrentModificationExceptions 的保证是一个巨大的保证:您可以编写简单的代码,而无需上面显示的同步块,并且知道事情会正常工作。

相关内容

最新更新