1.餓漢式(線程安全,調(diào)用效率高,不能延時加載)
public class SingletonDemo {
private static SingletonDemo instance=new SingletonDemo();
private SingletonDemo(){}
public static SingletonDemo getInstance(){
return instance;
}
}
2.懶漢式(線程安全,調(diào)用效率不高,能延時加載)
public class SingletonDemo2 {
//類初始化時,不初始化這個對象(延時加載,真正用的時候再創(chuàng)建)
private static SingletonDemo2 instance;
//構(gòu)造器私有化
private SingletonDemo2(){}
//方法同步,調(diào)用效率低
public static synchronized SingletonDemo2 getInstance(){
if(instance==null){
instance=new SingletonDemo2();
}
return instance;
}
}
3.雙重鎖
public class SingletonDemo3 {
//volatile防止指令重排序,內(nèi)存可見(緩存中的變化及時刷到主存,并且其他的內(nèi)存失效,必須從主存獲取)
private volatile static SingletonDemo3 instance;
private SingletonDemo3() {
}
public static SingletonDemo3 getInstance() {
//第一次判斷,假設(shè)會有好多線程,如果 instance 沒有被實例化,那么就會到下一步獲取鎖,只有一個能獲取到,
//如果已經(jīng)實例化,那么直接返回了,減少除了初始化時之外的所有鎖獲取等待過程
if (instance == null) {
synchronized (SingletonDemo3.class) {
//第二次判斷是因為假設(shè)有兩個線程A、B,兩個同時通過了第一個if,然后A獲取了鎖,進入然后判斷 instance 是null,他就實例化了instance,然后他出了鎖,
//這時候線程B經(jīng)過等待A釋放的鎖,B獲取鎖了,如果沒有第二個判斷,那么他還是會去new SingletonDemo3(),再創(chuàng)建一個實例,所以為了防止這種情況,需要第二次判斷
if (instance == null) {
instance = new SingletonDemo3();
}
}
}
return instance;
}
}
4.靜態(tài)內(nèi)部類(線程安全,調(diào)用效率高,可以延時加載)
public class SingletonDemo4 {
private static class SingletonHolder{
private static final SingletonDemo4 instance = new SingletonDemo4();
}
private SingletonDemo4(){}
public static SingletonDemo4 getInstance(){
return SingletonHolder.instance;
}
}
1.靜態(tài)內(nèi)部類如何實現(xiàn)線程安全
虛擬機會保證一個類的<clinit>()(類構(gòu)造器方法)方法在多線程環(huán)境中被正確地加鎖、同步,如果多個線程同時去初始化一個類,那么只會有一個線程去執(zhí)行這個類的<clinit>()方法,其他線程都需要阻塞等待,直到活動線程執(zhí)行<clinit>()方法完畢。
2.靜態(tài)內(nèi)部類能保證對象唯一性、線程安全又能延遲加載,是不是完美
由于是靜態(tài)內(nèi)部類的形式去創(chuàng)建單例的,故外部無法傳遞參數(shù)進去,傳參問題
是一大缺點。
5.枚舉類(線程安全,調(diào)用效率高,不能延時加載,可以天然的防止反射和反序列化調(diào)用)
public enum SingletonDemo5 {
//枚舉元素本身就是單例
INSTANCE;
//添加自己需要的操作
public void singletonOperation(){
}
}