Java 复制地图的线程安全方法

Java 复制地图的线程安全方法,java,guava,Java,Guava,我在项目中使用JDK 7、SQLite和番石榴 我有一个不到100个条目的树映射,它由一个“工作线程”每秒更新数百次。我现在正在编写一个组件(另一个线程——“DB线程”),它将每隔5秒或10秒将映射写入我的数据库 我知道我需要创建映射的深度副本,以便DB线程在工作线程继续工作时使用快照。我正在看的是,它有许多复制方法,但我不确定它们是否满足我在需要复制时在地图上同步的需要。是否有一种方法可以满足我的需要,或者我应该编写一个同步块来制作我自己的深度副本?来自javadoc: 请注意,此实现是不同步

我在项目中使用JDK 7、SQLite和番石榴

我有一个不到100个条目的树映射,它由一个“工作线程”每秒更新数百次。我现在正在编写一个组件(另一个线程——“DB线程”),它将每隔5秒或10秒将映射写入我的数据库

我知道我需要创建映射的深度副本,以便DB线程在工作线程继续工作时使用快照。我正在看的是,它有许多复制方法,但我不确定它们是否满足我在需要复制时在地图上同步的需要。是否有一种方法可以满足我的需要,或者我应该编写一个同步块来制作我自己的深度副本?

来自javadoc:

请注意,此实现是不同步的。如果有多个线程 访问地图 同时,如果至少有一个线程在结构上修改映射,则必须 外部同步。(结构修改是指添加或删除结构修改的任何操作 一个或多个映射;仅更改与现有键关联的值不是一个好方法 结构修改。)这通常是通过在某个 自然地封装了地图。如果不存在这样的对象,则应使用 Collections.synchronizedSortedMap方法。这最好在创建时完成,以防止 对地图的意外非同步访问:

   SortedMap m = Collections.synchronizedSortedMap(new TreeMap(...));

这取决于你想要什么:

如果您想要一个完全并发的映射(添加时无法读取等),您应该使用JSlain在我之前所说的

如果您只需要映射的当前快照,并且只要您使用的迭代器不会更改,您就不关心映射是否会被修改

然后使用

这将为每个迭代提供一个新的独立迭代器,因此即使真实映射发生了更改,您也不会注意到它


您将在下一次更新中看到它(本例中为5秒)。

您需要一个同步块。并且工作线程也必须在同一个锁上同步。除非您可以修改工作线程以遵守某种类型的锁(在制作副本时将它们排除在外),否则这是行不通的。但是工作线程肯定已经内置了某种锁定机制,所以您所需要做的就是将其用于复制。没有任何Guava
Maps
方法可以做类似的事情。大卫·林基斯的答案是正确的。实际上,如果您想在不同步的情况下从其他线程使用ConcurrentMap,则无论如何都需要一些
ConcurrentMap
。关于DB线程,您可以做一些其他的事情:让工作线程创建一个快照并将其发送到DB线程。但这肯定比使用
ConcurrentSkipListMap
更复杂,这肯定足够好。@biziclop-目前没有使用同步,因为循环中只有一个工作线程更新映射。使用synchronizedSortedMap是不够的:复制映射的wole代码块必须是已同步。我认为通过使用同步映射,您可以复制它,它将阻止其他试图访问它的线程。这样,您就不必修改调用者,使其与同步块一起使用,这会使代码臭烘烘。阅读javadoc:当用户迭代任何集合视图时,必须手动同步返回的排序映射。副本显然会在映射的条目上迭代,因此它需要同步。。。就像大卫·林基斯说的那样,如果你用的是同一张地图而不是副本,那就用吧。哇,我不知道那张。听起来像是他需要的。我相信这正是我想要的。你是对的,你以为我需要的只是当前的快照。我想知道他们是怎么做到的。。每次修改都会创建一个副本?我们可以检查实现,但我假设迭代器的每个请求都会创建一个副本。这是性能和内存之间的权衡。但是有一个有100个键的地图,意味着有100个副本。(假设你只添加…)我会创建一个新的。