同步集合是否总是需要同步块?

Is synchronized block always needed with synchronized collections?

考虑到有:

现在 - current 是这里的关键字 - 我需要直接流量 - 不能使用快照。

根据文档:(但我不确定我能做什么)

It is imperative that the user manually synchronize on the returned map when iterating over any of its collection views.

我真正需要的是每当地图被修改或被主线程、none迭代时57=] 线程可以访问它(锁定)。

同时,当主线程不接触所述映射时 - 所有 "mini" 线程都可以访问它们喜欢的映射(但它们不会以任何方式修改它 - 只是 iterate/read) .

但是现在 - 当 "mini" 正在迭代它时主线程想要修改地图时会发生什么?

这是否意味着我需要尽可能将地图放在同步块中?

ReadWriteLock 在这方面有帮助吗?请记住,查找 "mini" 个线程不能是快照。

如果您需要对 Map 的独占写入权限,那么您应该进行同步。您不需要使用 Collections.synchronizedMap(),只需确保您始终在同一个对象上同步:

private final Map<Whatever> myMap = new LinkedHashMap<>();

/* Your writer thread */
public void run()
{
    synchronized (myMap) {
       /* Write, iterate, whatever */
    }
}

/* Your reader thread */
public void run()
{
    synchronized (myMap) {
       /* Read stuff */
    }
}

只有一个线程可以同时进入给定对象的 synchronized 块。因此,您的作者线程和 reader 线程永远不会同时在您的地图上工作。

确保在 synchronized 块内做尽可能少的工作,并在完成后立即离开它们以减少争用。

请记住,同步(序列化)对 Map(或任何对象)的访问与使用 Map 上的方法返回的同步包装完全不同 =16=]。仅仅因为您使用 Collections.synchronizedMap() 返回的 Map 并不意味着您的代码是线程安全的。这同样适用于 ConcurrentHashMap。仅仅因为它的名称中包含 Concurrent,并不意味着您不能以 thread-unsafe 的方式使用它。

是的,您需要以某种方式同步以避免迭代时并发修改。

如果写入操作的频率远低于读取操作,那么 ReadWriteLock 可能是适合您的工具。

否则,synchronized-块可能是实现此目的的最简单方法。

Does this mean I need to put map in synchronized block whenever possible?

不是在任何可能的情况下,而是仅当您在该集合上获得 迭代器 时。 因为当您使用 synchronizedMap() API.

请求同步集合时,除了 iterator() 之外,所有其他方法都会为您同步

例如如果你想获得集合的大小,不需要在同步块中调用 yourmap.size() ,因为装饰器会为你处理同步。

您可以参考 Collections.java 进一步参考。

Collections.synchronizedMap() 将同步访问地图的每个方法,但是 Iterator 上的方法都是单独调用的,这就是为什么 you在迭代期间在地图上同步。

同步是一种独占锁,因此一次只能有一个线程迭代映射。如果您有许多 reader(迭代器)并希望它们并行执行,您绝对应该使用 ReadWriteLock 代替同步。并发实现对你来说不是一个可行的选择,因为你说 "can't use snapshots".

这意味着,不要使用 Collections.synchronizedMap() 包装 LinkedHashMap。相反,创建一个 ReentrantReadWriteLock,并且 always 获得围绕 any 使用地图的锁,使用 readLock() for readers(迭代、get()containsKey() 等),以及 writeLock() 用于增变器(put()remove()、迭代 remove()等)。