反面单例
反面單例
代碼
import java.util.ArrayList;
import java.util.List;
/**
* @since : 2023/11/17
**/
public class StupidSingleton {
private static final StupidSingleton instance = new StupidSingleton();
private static List<String> list = null;
private static Object object = null;
private StupidSingleton() {
list = new ArrayList<>();
object = new Object();
}
public synchronized static StupidSingleton getInstance() {
if (object == null) {
object = new Object();
}
return instance;
}
public void doSomething() {
list.add("Stupid");
}
}
問題點解析
doSomething拋出空指針異常
Java中字段、代碼塊、構造函數初始化順序是:
- 按照在代碼中的定義順序依次加載static變量和static代碼塊。
- 按照在代碼中的定義順序依次加載實例變量和實例代碼塊。
- 構造函數。
代入這段代碼中順序為:
- 初始化instance = new StupidSingleton()
- 執行構造函數
- 初始化list = null
- 初始化object = null
雖然result和object都在構造函數中初始化了,但是隨后又被賦值為null。
多線程下效率低
估計后來的修改者發現了object為空的問題,所以在getInstance中又做了初始化,這樣一來,多線程下就有問題,在getInstance上加個synchronized就好了。
getInstance是static的,這個時候配合synchronized鎖的就是StupidSingleton.class,多線程下效率必然低。
修改方案
- 把instance的初始化放在所有static變量定義的最后或者在靜態變量定義時直接初始化,不在構造函數中初始化。
- 刪除getInstance的synchronized。
- 刪除getInstance中對object的控制判斷和初始化。
總結
- 上一篇: 探索人工智能的世界:构建智能问答系统之实
- 下一篇: es笔记七之聚合操作之桶聚合和矩阵聚合