栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

以线程安全的方式延迟初始化Java映射

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

以线程安全的方式延迟初始化Java映射

双重检查锁定

双重检查锁定需要完成几个步骤才能正常工作,您错过了其中两个。

首先,您需要将其

someMap
变成一个
volatile
变量。这样一来,其他线程将在更改后但完成更改后看到更改。

private volatile Map<String, String> someMap = null;

您还需要

null
synchronized
块内进行第二次检查,以确保在等待进入同步区域时没有另一个线程为您初始化它。

    if (someMap == null) {        synchronized(this) { if (someMap == null) {

待使用前不要分配

在生成映射时,请在temp变量中构造它,然后在最后分配它。

     Map<String, String> tmpMap = new HashMap<String, String>();     // initialize the map contents by loading some data from the database.     // possible for the map to be empty after this.     someMap = tmpMap; }        }    }    return someMap.get(key);

解释为什么需要临时地图。完成这一行

someMap = newHashMap...
后,该字段将
someMap
不再为null。这意味着其他调用
get
将看到它,并且从不尝试进入该
synchronized
块。然后,他们将尝试从地图中获取数据,而无需等待数据库调用完成。

通过确保分配到

someMap
同步块中的最后一步,可以防止这种情况的发生。

unmodifiableMap

正如评论中所讨论的,出于安全考虑,最好将结果保存为,

unmodifiableMap
因为将来的修改将不是线程安全的。对于从未公开的私有变量,这不是严格要求的,但是对于将来仍然更安全,因为它将阻止人们稍后进入并更改代码而没有意识到。

 someMap = Collections.unmodifiableMap(tmpMap);

为什么不使用ConcurrentMap?

ConcurrentMap
使单个操作(即
putIfAbsent
)成为线程安全的,但它不满足此处的基本要求,即等到映射完全填充数据后才允许对其进行读取。

另外,在这种情况下,延迟初始化之后的Map不会再次被修改。这

ConcurrentMap
将为在此特定用例中不需要同步的操作增加同步开销。

为什么要 对此进行 同步?

没有理由。:)这是提出此问题的有效答案的最简单方法。

在私有内部对象上进行同步肯定是更好的做法。您已经在改进封装方面进行了权衡,以稍微增加内存使用量和对象创建时间。同步的主要风险

this
在于,它允许其他程序员访问您的锁对象,并可能尝试自己尝试对其进行同步。然后,这会导致他们的更新与您的更新之间发生不必要的争用,因此内部锁定对象会更安全。

实际上,尽管在许多情况下,单独的锁定对象是过大的。这是一个基于您的类的复杂性以及是否使用广泛而不是仅仅锁定on的简单性的判断调用

this
。如有疑问,您可能应该使用内部锁定对象并采取最安全的路线。

在课堂里:

private final Object lock = new Object();

在方法中:

synchronized(lock) {

对于

java.util.concurrent.locks
对象,在这种情况下它们不会添加任何有用的东西(尽管在其他情况下它们非常有用)。我们始终希望等到数据可用后,才能使用标准的同步块为我们提供所需的行为。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/569999.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号