最近一直在看很多第三方库代码,看到这段代码让我很困惑
Been looking at lot of third party library codes lately and see this code which is confusing me
所以这是来自 EventBus getDefault() 静态方法的一段代码,它 returns EventBus 的静态实例 class。
/** Convenience singleton for apps using a process-wide EventBus instance. */
public static EventBus getDefault() {
EventBus instance = defaultInstance;
if (instance == null) {
synchronized (EventBus.class) {
instance = EventBus.defaultInstance;
if (instance == null) {
instance = EventBus.defaultInstance = new EventBus();
}
}
}
return instance;
}
我看到代码首先检查实例是否为空,然后在同步块中再次执行相同的检查。为什么会这样。
这样写会怎样
/** Convenience singleton for apps using a process-wide EventBus instance. */
public static EventBus getDefault() {
EventBus instance = defaultInstance;
if (instance == null) {
synchronized (EventBus.class) {
instance = EventBus.defaultInstance = new EventBus();
}
}
return instance;
}
我的版本有问题吗?我在这里缺少什么?
在您的代码中,当 instance 为 null 时,两个线程可以同时进入 if 语句。然后,一个线程进入同步块初始化实例,而另一个线程被阻塞。当第一个线程退出同步块时,等待线程进入并创建另一个 Singleton 对象。请注意,当第二个线程进入同步块时,它不会检查实例是否为非空。
所以我们遵循双重检查初始化,它包括:
- 检查变量是否已初始化(未获取锁)。如果它被初始化,return它立即。
- 获取锁。
- 仔细检查变量是否已经初始化:如果另一个线程首先获得了锁,它可能已经完成了初始化。如果是这样,return初始化变量。
- 否则,初始化并 return 变量。
所以这是来自 EventBus getDefault() 静态方法的一段代码,它 returns EventBus 的静态实例 class。
/** Convenience singleton for apps using a process-wide EventBus instance. */
public static EventBus getDefault() {
EventBus instance = defaultInstance;
if (instance == null) {
synchronized (EventBus.class) {
instance = EventBus.defaultInstance;
if (instance == null) {
instance = EventBus.defaultInstance = new EventBus();
}
}
}
return instance;
}
我看到代码首先检查实例是否为空,然后在同步块中再次执行相同的检查。为什么会这样。
这样写会怎样
/** Convenience singleton for apps using a process-wide EventBus instance. */
public static EventBus getDefault() {
EventBus instance = defaultInstance;
if (instance == null) {
synchronized (EventBus.class) {
instance = EventBus.defaultInstance = new EventBus();
}
}
return instance;
}
我的版本有问题吗?我在这里缺少什么?
在您的代码中,当 instance 为 null 时,两个线程可以同时进入 if 语句。然后,一个线程进入同步块初始化实例,而另一个线程被阻塞。当第一个线程退出同步块时,等待线程进入并创建另一个 Singleton 对象。请注意,当第二个线程进入同步块时,它不会检查实例是否为非空。
所以我们遵循双重检查初始化,它包括:
- 检查变量是否已初始化(未获取锁)。如果它被初始化,return它立即。
- 获取锁。
- 仔细检查变量是否已经初始化:如果另一个线程首先获得了锁,它可能已经完成了初始化。如果是这样,return初始化变量。
- 否则,初始化并 return 变量。