在地图内同步集合

时间:2017-05-13 22:47:33

标签: java multithreading synchronization synchronized

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

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);
        }
    }

}

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

但是我的IDE警告我,这是 同步本地变量 使用此类同步时很难保证正确性< / EM> 即可。

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

3 个答案:

答案 0 :(得分:1)

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

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

来自文档:

  

与新的集合实现不同,Vector是同步。如果不需要线程安全实现,建议使用ArrayList代替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);

 }

答案 1 :(得分:1)

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

答案 2 :(得分:1)

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

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

如果ArrayList主要用于只读目的,那么-CopyOnWriteArrayList可能会胜过同步的ArrayList,但如果它的读写混合,那么Collections.synchronizedList()也很好。另一个区别是它如何迭代。

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