我试图理解这个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 方法。这只是一种说法还是有其他原因?
提前感谢您帮助解决此问题。
在代码示例中,不需要
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
读取并不比普通读取贵多少。