以下是说明情况的示例代码:
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> 即可。
有没有其他方法或良好做法来处理这种情况?
答案 0 :(得分:1)
Vector实现了一个动态数组。它与ArrayList类似,但有两点不同:
来自文档:
与新的集合实现不同,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返回的迭代器是一个故障安全迭代器。