当前位置: 首页 > 知识库问答 >
问题:

如何在一个读/写线程和一个只读线程之间同步Map?

游皓
2023-03-14

我有一个由线程a读取和更新的同步映射(通过< code > collections . synchronized Map()),线程B只能通过< code>Map.keySet()(只读)访问该映射。

我应该如何同步这个?文档中说key Set()(用于Collections.synchronized映射)“不需要在同步块中”。我可以把线程A的读/写访问放在同步块中,但这有必要吗?

我想,如果Map.keySet不需要同步(根据上面的文档链接),那么使用同步映射或同步块对我来说似乎很奇怪...

更新:我错过了必须同步密钥集的迭代,即使检索密钥集不需要同步。拥有 keySet 而无法查看它并不是特别令人兴奋,因此最终结果 = 需要同步。改用ConcurrentHashMap。

共有3个答案

薄鸿远
2023-03-14

文档是正确的。从Collections.synchronizedMap()返回的map将正确地对发送到原始Map的所有调用进行同步包装。但是,key Set()返回的set impl不具有相同的属性,因此您必须确保它是在相同的锁下读取的。

如果没有此同步,则无法保证线程 B 将永远看到线程 A 所做的任何更新。

您可能想要调查 ConcurrentHashMap。它正是针对此用例提供了有用的语义。在 CHM 中迭代集合视图(如 keySet())会提供有用的并发行为(“弱一致性”迭代器)。您将在迭代时遍历集合状态中的所有键,并且在创建迭代器后可能会也可能不会看到更改。

朱越
2023-03-14

这些文档告诉您如何正确同步需要原子的多步骤操作,在本例中是遍历映射:

Map m = Collections.synchronizedMap(new HashMap());
      ...
Set s = m.keySet();  // Needn't be in synchronized block
      ...
synchronized(m) {  // Synchronizing on m, not s!
    Iterator i = s.iterator(); // Must be in synchronized block
    while (i.hasNext())
        foo(i.next());
}

注意实际迭代必须如何在同步块中。文档只是说,获取<code>keySet()</code>是否在同步块中并不重要,因为它是<code>Map</code<的实时视图。如果映射中的键在所获得的键集的引用和同步块的开始之间发生变化,则键集将反映这些变化。

顺便说一下,您引用的文档仅适用于Map返回的MapCollections.synchronized。该语句不一定适用于所有Map

冯风史
2023-03-14

要创建一个真正的读/写与只读锁定的< code>Map包装器,您可以查看< code >集合用于< code>synchronizedMap()的包装器,并用< code > ReentrantReadWriteLock 替换所有的< code>synchronized语句。这是一件很好的工作。相反,您应该考虑改用< code>ConcurrentHashMap,它可以做所有正确的事情。

keySet() 而言,它不需要在同步块中,因为它已经被 Collections.synchronizedMap() 同步了。Javadocs 只是指出,如果你正在遍历映射,你需要在它上面同步,因为你正在执行多个操作,但是当你获得 keySet() 时你不需要同步,keySet() 被包装在一个 SyncdSet 类中,该类执行自己的同步。

最后,你的问题似乎在暗示,如果你只是阅读,就不需要同步。您必须记住,同步不仅可以防止竞争情况,还可以确保每个处理器正确地共享数据。即使您以只读方式访问< code>Map,如果任何其他线程正在更新它,您仍然需要对它进行同步。

 类似资料:
  • 问题内容: 说我有一个全局对象: 有一个线程定期运行以从远程获取新编号并更新(仅写入): 并且有一个或多个线程随机使用此全局变量(仅读取): 您可以看到我不使用任何锁或对其进行保护,对吗?是否有可能引起问题的潜在问题? 更新: 就我而言,读取线程必须实时获取最新的值并不是很重要。我的意思是,如果有任何问题(由于缺少锁定/同步而导致)使一个读取线程错过了该值,那就没关系了,因为它将有机会尽快运行相同

  • 本文向大家介绍python多线程同步之文件读写控制,包括了python多线程同步之文件读写控制的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了python多线程同步之文件读写控制的具体代码,供大家参考,具体内容如下 1、实现文件读写的文件ltz_schedule_times.py 2.1、不加锁对文件进行多线程读写。file_lock.py 得到结果: 文件写入结果: 以上结果可以看

  • 我有一个疑问相对于UI线程和其他线程之间的concurrency。 Ui主线程更新不同变量的值:-flol-long-boolean 我还有另一个线程,它读取同一个变量,并用它执行一些逻辑操作(不编辑它的值),然后用这个操作的结果发送本地广播消息。 是否存在并发问题???我必须使用同步方法和原子变量,否则就无关紧要了? 我反思这个问题,因为没有浮点基元的原子变量,也因为我害怕用错误的代码阻止Ui线

  • 我写了一个启动两个线程的代码片段;一个线程打印所有奇数,而另一个线程打印所有偶数。我使用了内在锁和线程通信命令的组合来实现两个线程的正确交叉。这是我的代码, 以下是我的问题: > 奇数线程在printOdd()函数中执行,而偶数线程在print偶数()函数中执行。我对两个线程都使用一个内在锁;我不明白两个线程怎么能同时存在于各自的同步块中,因为使用了相同的锁。 我从代码中删除了线程通信语句(通知,

  • 问题内容: 在面试中被问到这个问题,试图解决…但是没有成功。我想到了使用CyclicBarrier 有三个线程T1打印1,4,7 … T2打印2,5,8 …,T3打印3,6,9…。您如何同步这三个来打印序列1,2,3,4,5,6,7,8,9…。 我尝试编写并运行以下代码 输出 谁能帮助我纠正错误? 类似的 线程同步查询-同步三个线程以打印012012012012.....无法正常工作 问题答案:

  • 在采访中被问到这个问题,试图解决它。。。但并不成功。我想用自行车旅行车 有三个线程T1打印1,4,7... T2打印2,5,8......和T3打印3,6,9......你如何将这三个同步到打印序列1,2,3,4,5,6,7,8,9...... 我试着写作 输出 有人能帮我纠正错误吗? 类似的Ques线程同步-将三个线程同步到打印012。。。。。不起作用