为什么lockStatic在Android中是不稳定的?

问题描述 投票:0回答:1

我试图理解这个Android实现,但我只是不明白为什么静态字段lockStatic是易失性的,因为它的使用只能通过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 方法。这只是一种说法还是有其他原因?

提前感谢您帮助解决此问题。

弱完整意图服务

java android multithreading
1个回答
2
投票

在代码示例中,不需要

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

当然,这有点过分了。因此,除非您确切知道自己在做什么,否则请谨慎行事并使用

volatile
volatile
读取并不比普通读取贵多少。

© www.soinside.com 2019 - 2024. All rights reserved.