考虑到:
Collections.synchronizedMap(new LinkedHashMap<>());
Thread
现在 - 当前是关键字 - 我需要直接流量 - 无法使用快照。
根据文档:(但我不确定我能做什么)
当迭代任何集合视图时,用户必须手动同步返回的地图。
我需要的是,只要地图被主线程修改或迭代,“迷你”线程都无法访问它(锁定)。
同时,当主线程未触及所述地图时 - 所有“迷你”线程都可以访问地图但是他们喜欢(但他们不会以任何方式修改它 - 只是迭代/读取)。
但是现在 - 当主线程想要修改地图而“迷你”迭代它时会发生什么?
这是否意味着我需要尽可能将地图放在同步块中?
ReadWriteLock会在这里提供帮助吗?请记住,查找“迷你”线程不能是快照。
答案 0 :(得分:1)
如果您需要对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
块。因此,您的作者线程和读者线程将永远不会在您的地图上同时工作。
确保在synchronized
区块内尽可能少地完成工作,并在完成后尽快离开,以减少争用。
请记住,与Map
上的方法返回的同步包装器相比,Collections
(或任何对象)的同步(序列化)访问完全不同。仅仅因为您使用Map
返回的Collections.synchronizedMap()
并不意味着您的代码是线程安全的。这同样适用于ConcurrentHashMap
。仅因为名称中有Concurrent
,并不意味着您不能以线程不安全的方式使用它。
答案 1 :(得分:1)
Collections.synchronizedMap()
会同步访问地图的每个方法,但是Iterator
上的方法都是单独调用的,这就是你必须在地图上同步的原因在迭代期间。
同步是一个独占锁,因此只有一个线程可以一次迭代地图。如果你有许多读者(迭代器)并希望它们并行执行,你肯定应该使用ReadWriteLock
替换同步。并发实现对你来说不是一个可行的选择,因为你说&#34;不能使用快照&#34;。
这意味着,请勿使用LinkedHashMap
包裹Collections.synchronizedMap()
。相反,创建一个ReentrantReadWriteLock
,并且始终获取围绕任何使用地图的锁定,使用readLock()
作为读者(迭代,{{1} },get()
等)和containsKey()
用于mutators(writeLock()
,put()
,与remove()
的迭代等)。
答案 2 :(得分:0)
是的,您需要以某种方式进行同步,以避免在迭代时进行并发修改。
如果写入操作的频率低于读取操作,那么.mdf
可能是适合您的工具。
否则,ReadWriteLock
- 块可能是实现此目的的最简单方法。
答案 3 :(得分:0)
这是否意味着我需要尽可能将地图放在同步块中?
不是在任何可能的情况下,但仅在您在该集合上获得迭代器时。 因为除了iterator()之外,当您使用synchronizedMap()API请求同步集合时,所有其他方法都会为您同步。
例如如果要获取集合的大小,则不需要在synchronized块中调用yourmap.size(),因为装饰器会为您处理同步。
您可以参考Collections.java进一步参考。