【问题标题】:Why is lockStatic volatile in android?为什么lockStatic在android中不稳定?
【发布时间】:2016-11-22 20:26:05
【问题描述】:

我试图理解这个 android 实现,但我就是不明白为什么静态字段 lockStatic 是 volatile,因为它的使用只能通过 getLock 方法并且它是一个同步块,所以应该没有并发或对象发布问题。

abstract public class WakefulIntentService extends IntentService {
    abstract protected void doWakefulWork(Intent intent);
    static final String NAME=
      "com.commonsware.cwac.wakeful.WakefulIntentService";
    static final String LAST_ALARM="lastAlarm";

    private static volatile PowerManager.WakeLock lockStatic=null;

    synchronized private static PowerManager.WakeLock getLock(Context context) {
       if (lockStatic == null) {
           PowerManager mgr = (PowerManager)context.getSystemService(Context.POWER_SERVICE);

           lockStatic=mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, NAME);
           lockStatic.setReferenceCounted(true);
       }

       return(lockStatic);
    }

如果允许 lockStatic 以任何其他方式访问,我认为只有 volatile 需要,但它的私有且唯一处理它的方法是 getLock 方法。这只是一个断言还是背后有其他原因?

提前感谢您为解决此问题提供的任何帮助。

WeakfullIntentService

【问题讨论】:

  • 我很确定我这样做是为了支持双重检查锁定实现。然而,一般来说,问“为什么开发人员 X 做 Y 事?”对于堆栈溢出来说不是很好。唯一能明确回答的人是开发者 X。在这种情况下,我是开发者 X,并且我在几年前编写了该代码。没有其他人可以明确回答。
  • @CommonsWare 不过,当主要框架代码的作者出现解释时,这还算不错。

标签: java android multithreading


【解决方案1】:

在代码示例中,不需要volatile,因为该变量只能在该synchronized 块中访问。

但是,synchronized 可能有点过于昂贵,尤其是考虑到对该方法的多数调用只是读取变量并返回。每次阅读都用synchronized 包围感觉太沉重了。因此我们有所谓的双重检查模式,它在大多数情况下都会避免synchronized

if(var==null)
    synchronized(lock)
        if(var==null)         // double-check
            var = something
return var

(但是,OP 的代码示例不是双重检查锁定;它是全时锁定。)

在双重检查锁定中,通常var 应该是volatile——但并非总是如此。如果分配给它的对象是原始的(如int)或不可变的(如String),则非易失性是可以的。

还有更多情况下非易失性是可以的。这需要对用例进行仔细评估。例如,java.util.concurrent(例如ReentrantLock)中的所有实用程序类的设计方式使其能够在“不安全的发布”中存活。当它们用于双重检查锁定模式时,它们不必是volatile。看到WakeLock的源码,我相信在双重检查锁定中也不需要volatile

当然,这有点过分了。因此,除非您确切知道自己在做什么,否则请放心使用volatilevolatile 读取并不比普通读取贵多少。

【讨论】:

  • 另请注意,“volatile”并不为所有版本的 Android(尤其是较旧的 Dalvik VM 实现)提供内存可见性保证,因为 Android 不遵守 Java 内存模型。过去我对此感到很恼火,因为 volatile 关键字基本上被 VM 忽略了,如果您在 Android 上需要 volatile 语义,最好使用“AtomicReference”或其他 java.util.concurrent AtomicXXX 类。
  • @GameSalutes - 太糟糕了:) 考虑到它拥有多少资金和人才,我会认为谷歌比 Sun 做得更好。
  • 确实如此。至少原子类提供了实现者必须遵守的契约,而且我已经在 Android 上成功地使用了它们,并且从那以后就没有使用过 volatile 。这是一个讨论它的线程:stackoverflow.com/questions/6973667/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-01-08
  • 2013-10-20
  • 2011-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多