同步地图内的集合

Synchronizing on collection inside map

下面是说明情况的示例代码:

public class ConnectionRegistry {

    private ConcurrentMap<String, List<Connection>> registry = new ConcurrentHashMap<>();

    public List<Connection> find(String key) {
        List<Connection> connections = registry.get(key);
        if (null == connections) {
            return Collections.emptyList();
        }
        synchronized(connections) {
            return new ArrayList(originalCopy);
        }
    }

    public void register(String key, Connection connection) {
        List<Connection> connections = registry.get(key);
        if (null == connections) {
            List<Connection> newConnections = new ArrayList<>();
            connections = registry.putIfAbsent(key, newConnections);
            if (null == connections) {
                connections = newConnections;
            }
        }
        synchronized(connections) {
            connections.add(connection);
        }
    }

}

在上面的代码中,我有一个注册表来管理按键索引的连接。我想让它线程安全,所以我使用了 ConcurrentMap 数据结构,除了地图之外,我想确保地图中的 List 也是线程安全的,因此我使用synchronize关键字如上源码所示

但是我的 IDE 警告我这是对局部变量 和 [= 的 同步22=]使用这种同步时很难保证正确性

有没有其他方法或好的做法来处理这种情况?

Vector 实现了一个动态数组。它类似于ArrayList,但有两点不同:

  • 向量已同步。
  • Vector 包含许多不属于集合框架的遗留方法。

来自文档:

Unlike the new collection implementations, Vector is synchronized. If a thread-safe implementation is not needed, it is recommended to use ArrayList in place of Vector.

稍作改动,代码将是:

public class ConnectionRegistry {

    private ConcurrentMap<String, List<Connection>> registry = new ConcurrentHashMap<>();

    public List<Connection> find(String key) {
        List<Connection> connections = registry.get(key);
        if (null == connections) {
            return Collections.emptyList();
        }

        return new Vector<Connection>(originalCopy);

    }

    public void register(String key, Connection connection) {
        List<Connection> connections = registry.get(key);
        if (null == connections) {
            List<Connection> newConnections = new Vector<Connection>();
            connections = registry.putIfAbsent(key, newConnections);
            if (null == connections) {
                connections = newConnections;
            }
        }

        connections.add(connection);

 }

就像ConcurrentHashMap一样,你可以使用CopyOnWriteArrayList同步ArrayList。 CopyOnWriteArrayList 提供与 ArrayList 相同的线程安全性。

如果您需要一个同步列表,您可以通过调用 Collections.synchronizedList() 或使用上面提到的 vector answer.Vector 和同步 ArrayList 比它们的并发副本 CopyOnWriteArrayList 慢得多,因为锁定了整个收集例如整个列表所以即使它不允许多次读取所以你可以考虑并发收集永远不会锁定整个地图或列表。

他们通过使用锁剥离等技术实现线程安全,或者在 CopyOnWriteArrayList 中允许多个 reader 线程在不同步的情况下读取,当发生写入时,它会复制整个 ArrayList 并与更新的 ArrayList 交换。

如果 ArrayList 主要用于只读目的,

-CopyOnWriteArrayList 可能会胜过同步的 ArrayList,但如果它混合读写,那么 Collections.synchronizedList() 一个也不错。另一个区别是它如何迭代。

-从同步 ArrayList 返回的迭代器是快速失败的,但 CopyOnWriteArrayList 返回的迭代器是故障安全迭代器。