Java 同步集合是否始终需要同步块?
考虑到:Java 同步集合是否始终需要同步块?,java,synchronized,Java,Synchronized,考虑到: Collections.synchronizedMap(新LinkedHashMap()) 主循环线程 在上面的映射上执行计划任务(来自阻塞队列)。 任务基本上可以是您可以使用map执行的任何操作(也可以迭代和更新其中的值) 多个循环“迷你”线程 需要不时在地图的当前元素上查找(仅迭代,无编辑) 现在-current是这里的关键字-我需要直接流-不能使用快照 根据文件:(但我不确定我能做什么) 当用户迭代任何集合视图时,必须手动同步返回的映射 我确切需要的是,每当主线程
Collections.synchronizedMap(新LinkedHashMap())代码>
- 主循环
线程
- 在上面的映射上执行计划任务(来自阻塞队列)。
- 任务基本上可以是您可以使用map执行的任何操作(也可以迭代和更新其中的值)
- 在上面的映射上执行计划任务(来自阻塞队列)。
- 多个循环“迷你”线程
- 需要不时在地图的当前元素上查找(仅迭代,无编辑)
ReadWriteLock在这里有帮助吗?请记住,“迷你”线程的查找不能是快照。如果您需要对
映射的独占写入访问权,则应同步。您不需要使用集合。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 */
}
}
private final Map myMap=new LinkedHashMap();
/*你的书写线程*/
公开募捐
{
已同步(myMap){
/*写,迭代,随便什么*/
}
}
/*你的读者线程*/
公开募捐
{
已同步(myMap){
/*阅读材料*/
}
}
只有一个线程可以同时为给定对象输入同步的块。因此,您的写入线程和读取线程将永远不会同时在地图上工作
确保在synchronized
块中尽可能少地执行工作,并在完成后立即将其保留,以减少争用
请记住,对映射
(或任何对象)的同步(序列化)访问与使用集合上的方法返回的同步包装器完全不同。仅因为您使用的是集合.synchronizedMap()
返回的映射
,并不意味着您的代码是线程安全的。这同样适用于ConcurrentHashMap
。仅仅因为它的名称中有Concurrent
,并不意味着您不能以线程不安全的方式使用它。是的,您需要以某种方式进行同步,以避免在迭代时并发修改
如果写操作的频率远低于读操作,那么ReadWriteLock
可能是适合您的工具
否则,synchronized
-块可能是实现这一点的最简单方法
这是否意味着我需要尽可能地将地图放入同步块中
不是在任何可能的地方,而是仅当您在该集合上获得迭代器时。
因为当您使用synchronizedMap()API请求同步的集合时,除了iterator()之外,所有其他方法都是同步的
例如,如果要获取集合的大小,则无需在同步块中调用yourmap.size(),因为装饰程序会为您处理同步
您可以参考以获取进一步的参考。集合。synchronizedMap()
将同步对映射的每个方法的访问,但是,迭代器上的方法都是单独调用的,这就是为什么在迭代期间必须在映射上同步的原因
同步是一个独占锁,因此一次只能有一个线程迭代映射。如果您有许多读卡器(迭代器),并且希望它们并行执行,那么您肯定应该使用。并发实现对您来说不是一个可行的选择,因为您说过“不能使用快照”
这意味着,不要使用Collections.synchronizedMap()
包装LinkedHashMap
。相反,创建一个映射,并始终围绕映射的任何使用获取锁,为读卡器使用readLock()
(迭代,get()
,containsKey()
,等等),并为变体使用writeLock()
(put()
,remove()
,使用remove()
进行迭代,等等).当您忙于查看并发包时,您忘记了基本解决方案。请随意使用锁
,但同步可能就足够了。如果发现存在大量争用,可以切换到另一种并发控制机制。Collections.synchronizedMap()
只是一种使用synchronized
块“自动”包装映射上所有方法的方法。不使用集合。synchronizedMap()
只是意味着你必须自己做,这意味着:1)更多的代码。2) 容易出错(您可能会忘记执行此操作)因此,我认为这个答案并不是这个问题的好答案。同样的缺点也适用于使用RWL。在Map
操作上手动同步与使用方法同步的Map
不同。的确,使用ReadWriteLock
您没有太多选择,但您的答案根本不是关于RWL,而是提倡手动synchronized
块而不是使用synchronizedMap()
,这就是为什么我认为答案是不好的。关于ReentrantReadWriteLock,我使用了它