1还栓、餓漢式
- 優(yōu)點(diǎn):類加載的時(shí)候完成實(shí)例化碌廓,避免了線程同步問題
- 缺點(diǎn):在類加載的時(shí)候就完成實(shí)例化,沒有達(dá)到Lazy Loading的效果剩盒,如果該類未使用則造成了內(nèi)存浪費(fèi)
可以通過靜態(tài)變量和靜態(tài)代碼塊兩種方式實(shí)現(xiàn)谷婆,效果一樣
public class Singleton1 {
//方式1:通過靜態(tài)變量方式創(chuàng)建
private static final Singleton1 INSTANCE = new Singleton1();
//方式2:通過靜態(tài)代碼塊的方式,效果和方法1一樣
// private static final Singleton1 INSTANCE;
//
// static {
// INSTANCE = new Singleton1();
// }
/**
* 私有的構(gòu)造方法辽聊,防止產(chǎn)生多個(gè)對(duì)象
*/
private Singleton1() {
}
/**
* 通過該方法獲得實(shí)例
*
* @return
*/
public static Singleton1 getInstance() {
return INSTANCE;
}
public void doSomething() {
}
}
可通過如下方式纪挎,在多個(gè)線程中創(chuàng)建多個(gè)單例對(duì)象,查看創(chuàng)建的對(duì)象hashCode是否相同判斷是否為單例
Executor executor = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
executor.execute(new Runnable() {
@Override
public void run() {
//測(cè)試餓漢式單例
Singleton1 singleton1 = Singleton1.getInstance();
Singleton1 singleton2 = Singleton1.getInstance();
System.out.println(singleton1.hashCode() + "\t-----\t" + singleton2.hashCode());
}
});
}
打印結(jié)果如下身隐,不同線程下的Singleton1對(duì)象都是同一個(gè)HashCode,表示是全局單例
2007961061 ----- 2007961061
2007961061 ----- 2007961061
2007961061 ----- 2007961061
2007961061 ----- 2007961061
2007961061 ----- 2007961061
2007961061 ----- 2007961061
2007961061 ----- 2007961061
2007961061 ----- 2007961061
2007961061 ----- 2007961061
2007961061 ----- 2007961061
2廷区、懶漢式-線程不安全
- 優(yōu)點(diǎn):做到了懶加載
- 缺點(diǎn):多線程使用的時(shí)候會(huì)產(chǎn)生多個(gè)實(shí)例,實(shí)際開發(fā)中不要使用這種方案
public class SingLeton2 {
private static SingLeton2 INSTANCE;
private SingLeton2() {
}
public static SingLeton2 getInstance() {
if (INSTANCE == null) {
INSTANCE = new SingLeton2();
}
return INSTANCE;
}
}
多線程創(chuàng)建此單例hashcode如下贾铝,存在hashCode不一致的問題,所有沒有做到全局單例
1337000531 ----- 1337000531
1337000531 ----- 1337000531
1337000531 ----- 1337000531
1337000531 ----- 1337000531
1337000531 ----- 1337000531
1523178316 ----- 1523178316
1337000531 ----- 1337000531
1337000531 ----- 1337000531
1337000531 ----- 1337000531
1337000531 ----- 1337000531
3埠帕、懶漢式 線程安全
- 優(yōu)點(diǎn):加了同步垢揩,線程安全
- 缺點(diǎn):效率太低,開發(fā)中不推薦使用這種寫法
public class Singleton3 {
private static Singleton3 INSTANCE;
private Singleton3() {
}
public static synchronized Singleton3 getINSTANCE() {
if (INSTANCE == null) {
INSTANCE = new Singleton3();
}
return INSTANCE;
}
}
下面這種方式敛瓷,雖然加鎖了但是還是存在線程不安全的問題,同一時(shí)刻不同的線程走到if(instance==null)這一步時(shí)叁巨,還是會(huì)創(chuàng)建不同的對(duì)象
//方式二 線程不安全
static class Singleton7{
private static Singleton7 instance;
private Singleton7(){}
public static Singleton7 getInstance() {
if(instance==null){
synchronized (Singleton7.class){
instance=new Singleton7();
}
}
return instance;
}
}
4、雙重檢查
- 優(yōu)點(diǎn):線程安全呐籽,延遲加載锋勺,效率高
- 開發(fā)中推薦使用這種方案
public class Singleton4 {
private static volatile Singleton4 instance;
private Singleton4() {
}
public static Singleton4 getInstance() {
if (instance == null) {
synchronized (Singleton4.class) {
if (instance == null) {
instance = new Singleton4();
}
}
}
return instance;
}
}
5、靜態(tài)內(nèi)部類
- 優(yōu)點(diǎn):線程安全狡蝶,也做到了懶加載庶橱,開發(fā)中推薦使用
public class Singleton5 {
private Singleton5() {
}
private static class Singleton5Instance {
private static final Singleton5 INSTANCE = new Singleton5();
}
public static Singleton5 getInstance() {
return Singleton5Instance.INSTANCE;
}
}
6、枚舉方式創(chuàng)建單例
- <<Effective Java>>推薦使用這種方式創(chuàng)建單例贪惹,項(xiàng)目中推薦使用
public enum Singleton6 {
INSTANCE;
public void doSomething() {
System.out.println("枚舉創(chuàng)建");
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}