單例模式
單例模式(Singleton)的定義:一個類只能有一個實例,並且這個實例由這個類創建。在軟件設計中,爲了節約空間、保證數據的一致性,許多類只能擁有一個實例,這種設計就採用單例模式。單例模式的實現方法是:1、使類的構造方法私有化;2、創建屬於此類類型的靜態成員對象;3、提供靜態方法獲取對象。
單例模式的實現
常用的單例模式的實現方式有4種,其中包括懶漢式、餓漢式、枚舉實現、雙重檢測方式,下面進行介紹。
餓漢式
該方式的特點是在加載類的時候就創建對象,此種方式是線程安全的。但是在類的創建過程複雜、繁瑣時,這種方式導致類的加載過於緩慢。
/**
* 單例模式餓漢式
*/
public class Singleton {
private static final Singleton instance = new Singleton() ;
private Singleton(){}
public static Singleton getInstance(){
try {
Thread.sleep(3000); //模擬創建延遲
} catch (InterruptedException e) {
e.printStackTrace();
}
return instance;
}
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(()->{
ints1 = Singleton.getInstance();
});
Thread thread2 = new Thread(()->{
ints2 = Singleton.getInstance();
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(ints1 == ints2);
System.out.println(ints1);
System.out.println(ints2);
}
}
枚舉方式
這種方式有點和餓漢式一樣,都是簡單實現,同時是線程安全的。
// 枚舉實現方式
public enum SingletonEnum {
Instance();
SingletonEnum getInstance(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return Instance;
}
}
//測試類
public class Singleton {
private static SingletonEnum inst1;
private static SingletonEnum inst2;
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(()->{
inst1 = SingletonEnum.getInstance();
});
Thread thread2 = new Thread(()->{
inst2 = SingletonEnum.getInstance();
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(inst1 == inst2);
System.out.println(inst1);
System.out.println(inst2);
}
}
懶漢式
這種方式的特點是在需要第一次需要對象的時候加載類。爲了保證線程安全,對實例對象使用volatile關鍵字,同時在獲取實例對象的方法上使用synchronized關鍵字。這種方式的缺點是在方法上加鎖過於頻繁,其實只需要在第一次創建對象的時候需要將方法加鎖,而後面獲取對象的操作是不需要加鎖的,這樣會降低效率。
/**
* 單例模式懶漢式
*/
public class Singleton {
private static volatile Singleton instance = null;
private static Singleton ints1;
private static Singleton ints2;
private Singleton(){}
public static synchronized Singleton getInstance(){
try {
Thread.sleep(3000); //模擬創建延遲
} catch (InterruptedException e) {
e.printStackTrace();
}
if(instance == null){
instance = new Singleton();
}
return instance;
}
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(()->{
ints1 = Singleton.getInstance();
});
Thread thread2 = new Thread(()->{
ints2 = Singleton.getInstance();
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(ints1 == ints2);
System.out.println(ints1);
System.out.println(ints2);
}
}
雙重檢測方式
這種方式是改造懶漢式創建方式,只在第一次創建時加鎖,後面獲取實例不用加鎖便能獲取對象,改善了獲取類的效率。
**
* 單例模式雙重檢測方式
*/
public class Singleton {
private static volatile Singleton instance = null;
private static Singleton ints1;
private static Singleton ints2;
private Singleton(){}
public static Singleton getInstance(){
if(instance == null){
synchronized (Singleton.class){
if(instance == null){
try {
Thread.sleep(3000); //模擬創建延時
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new Singleton();
}
}
}
return instance;
}
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(()->{
ints1 = Singleton.getInstance();
});
Thread thread2 = new Thread(()->{
ints2 = Singleton.getInstance();
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(ints1 == ints2);
System.out.println(ints1);
System.out.println(ints2);
}
}