gpt4 book ai didi

java - 为什么在 Facebook YearClass 中声明非线程 - volatile 参数

转载 作者:行者123 更新时间:2023-11-29 09:28:36 24 4
gpt4 key购买 nike

我探索了 Facebook 开源 device-year-class并发现了一些我想问的有趣问题。

这是一个非常简单的类,可以进行一些计算并返回您设备的年份

public class YearClass {  
.
.

private volatile static Integer mYearCategory;

public static int get(Context c) {
if (mYearCategory == null) {
synchronized(YearClass.class) {
if (mYearCategory == null) {
mYearCategory = categorizeByYear(c);
}
}
}
return mYearCategory;
}

}

为什么他们检查两次 mYearCategory == null 条件以及为什么这个变量声明为 volatile?它不是从不同的线程初始化的,我们在应用程序生命周期中没有对该值进行更改,我们只是第一次检索它......为什么确保我们从内存读取/写入它如此重要,如果没有 volatile 会发生什么。还有为什么我们需要synchronized呢?没有其他线程可以更改它的风险,它仅供阅读。

最佳答案

为什么会有static volatile变量?

如果您通过多个线程访问静态值,则每个线程都可以拥有其本地缓存副本。为避免这种情况,您可以将变量声明为 static volatile,这将强制线程每次读取全局值。

现在来回答你的第二个问题。为什么要检查 null 两次?这称为双重检查锁定优化。

什么是双重检查锁定?

          public static int get(Context c) {
if (mYearCategory == null) {
synchronized(YearClass.class) {
if (mYearCategory == null) {
mYearCategory = categorizeByYear(c);
}
}
}
return mYearCategory;
}

考虑一下,对 get(Context c) 的第一次调用将创建该对象,并且只有少数几个在此期间尝试访问它的线程需要同步;之后所有的调用都得到了对成员变量的引用。由于在某些极端情况下同步方法可能会使性能降低 100 倍或更高,因此每次调用此方法时获取和释放锁的开销似乎是不必要的:一旦初始化完成,获取和释放锁就会出现不必要。许多程序员尝试通过以下方式优化这种情况:

  1. 检查变量是否已初始化(未获得锁)。如果已初始化,则立即返回。
  2. 获取锁。
  3. 仔细检查变量是否已经初始化:如果另一个线程首先获得了锁,它可能已经完成了初始化。如果是,则返回初始化变量。
  4. 否则,初始化并返回变量。

关于java - 为什么在 Facebook YearClass 中声明非线程 - volatile 参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35812441/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com