單例模式作爲java設計模式裏最常用的一種設計模式之一,在我們日常的開發中大量被使用,現在我想從理論到實踐重新梳理一下這個知識點,幫助基礎薄弱的自己進一步加深理解。
什麼是單例模式(Singleton)
“單例”,顧名思義就是隻有一個類的實例
單:唯一
例:實例
單例設計模式:確保某一個類只有一個實例,自行實例化並向整個系統提供這個實例,同時也提供全局訪問的方法以供調用。
要點
- 確保一個類只能有一個實例
- 必須是自行創建這個實例,避免外部創建實例或者被子類繼承從而創建額外實例
- 必須自行的向整個系統提供這個實例
從代碼實現角度來看:
- 將單例類的構造函數私有化,這樣外部代碼就無法直接用new來實例化該對象
- 定義一個該類的靜態私有對象
- 提供一個靜態的公共方法用於創建;獲取類的靜態私有對象
有多種實現方式,主要分爲以下兩大類:
- 餓漢式:
優點:直接創建對象,不存在線程安全問題,在類創建好的同時對象生成,調用獲得對象實例的方法反應速度快,代碼簡潔。
缺點:資源利用效率低,用不用的都創建了;系統啓動加載時間可能會比較長
- 懶漢式:
優點:延遲加載對象,資源利用效率高
缺點:代碼相對複雜一點;線程不安全,要加鎖控制,這就會導致性能受到影響;第一次加載類的對象反應稍慢
餓漢式代碼demo
package com.java_foundation.singleton;
/**
* @program: java_foundation
* @description:
* 餓漢式:直接創建對象,不管是否使用該對象都會創建
* 特點:1)構造器私有化
* 2)自行創建,並用靜態變量保存
* 3)向外部提供這個實例
* 4)可以使用final修飾,強調這是一個單例
* @author: xiongbangwen <Email>[email protected]</Email>
* @create: 2020-05-30 20:35
**/
public class Singleton_1 {
public static final Singleton_1 INSTANCE = new Singleton_1();
private Singleton_1(){
System.out.println("單例模式");
}
}
枚舉式單例
package com.java_foundation.singleton;
/**
* @program: java_foundation
* @description: 枚舉
* 表示該類型的對象是有限的幾個
* 當限定爲一個時,就變成了單例
* 重寫了toString()方法,一般返回的是常量名字
* @author: xiongbangwen <Email>[email protected]</Email>
* @create: 2020-05-30 20:43
**/
public enum Singleton_2 {
INSTANCE;
}
懶漢式demo(線程不安全)
package com.java_foundation.singleton;
import java.io.IOException;
import java.util.Properties;
/**
* @program: java_foundation
* @description: 靜態代碼塊的單例
* @author: xiongbangwen <Email>[email protected]</Email>
* @create: 2020-05-30 20:52
**/
public class Singleton_3 {
public static final Singleton_3 INSTANCE;
private String info;
static {
try {
Properties pro = new Properties();
pro.load(Singleton_3.class.getClassLoader().getResourceAsStream("singleton.properties"));
INSTANCE = new Singleton_3(pro.getProperty("info"));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private Singleton_3(String info){
this.info = info;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
@Override
public String toString() {
return "Singleton_3{" +
"info='" + info + '\'' +
'}';
}
}
懶漢式demo(加鎖版)
package com.java_foundation.singleton;
/**
* @program: java_foundation
* @description: 懶漢式:延遲創建這個實例對象,創建一次就不再創建,有線程安全問題
* 1)構造器私有化
* 2)用一個靜態變量保存這個唯一的實例
* 3)提供一個靜態方法去獲取這個實例對象
* @author: xiongbangwen <Email>[email protected]</Email>
* @create: 2020-05-30 21:25
**/
public class Singleton_5 {
private static Singleton_5 instance;
private Singleton_5(){
}
public static Singleton_5 getInstance(){
if(instance == null) {
synchronized (Singleton_5.class) {
if (instance == null) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new Singleton_5();
}
}
}
return instance;
}
}
懶漢式優化,用靜態內部類實現
package com.java_foundation.singleton;
/**
* @program: java_foundation
* @description: 在內部類被加載時和初始化,才創建INSTANCE對象
* 靜態內部類不會自動隨着外部類的加載和初始化而初始化,它是要單獨去加載和初始化的
* 因爲是在內部類加載和初始化時創建的,因此線程是安全的
* @author: xiongbangwen <Email>[email protected]</Email>
* @create: 2020-05-30 21:42
**/
public class Singleton_6 {
private Singleton_6(){
}
private static class Inner{
private static final Singleton_6 INSTANCE = new Singleton_6();
}
public static Singleton_6 getInstance(){
return Inner.INSTANCE;
}
}
Test測試類
package com.java_foundation.singleton;
import java.util.concurrent.*;
/**
* @program: java_foundation
* @description: 測試
* @author: xiongbangwen <Email>[email protected]</Email>
* @create: 2020-05-30 20:41
**/
public class Test {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// Singleton_1 s1 = Singleton_1.INSTANCE;
// System.out.println(s1);
// Singleton_2 s2 = Singleton_2.INSTANCE;
// System.out.println(s2);
// Singleton_3 s3 = Singleton_3.INSTANCE;
// System.out.println(s3);
// Singleton_4 s4 = Singleton_4.getInstance();
// Singleton_4 s5 = Singleton_4.getInstance();
// System.out.println(s4);
// System.out.println(s5);
//懶漢式單線程沒有問題
// Callable<Singleton_4> c = new Callable<Singleton_4>() {
// @Override
// public Singleton_4 call() throws Exception {
// return Singleton_4.getInstance();
// }
// };
// ExecutorService es = Executors.newFixedThreadPool(2);
// Future<Singleton_4> f1 = es.submit(c);
// Future<Singleton_4> f2 = es.submit(c);
// Singleton_4 s6 = f1.get();
// Singleton_4 s7 = f2.get();
// System.out.println(s6);
// System.out.println(s7);
// System.out.println(s6==s7);
//加鎖
// Callable<Singleton_5> c = new Callable<Singleton_5>() {
// @Override
// public Singleton_5 call() throws Exception {
// return Singleton_5.getInstance();
// }
// };
// ExecutorService es = Executors.newFixedThreadPool(2);
// Future<Singleton_5> f1 = es.submit(c);
// Future<Singleton_5> f2 = es.submit(c);
// Singleton_5 s6 = f1.get();
// Singleton_5 s7 = f2.get();
// System.out.println(s6);
// System.out.println(s7);
// System.out.println(s6==s7);
//靜態內部類形式
Callable<Singleton_6> c = new Callable<Singleton_6>() {
@Override
public Singleton_6 call() throws Exception {
return Singleton_6.getInstance();
}
};
ExecutorService es = Executors.newFixedThreadPool(2);
Future<Singleton_6> f1 = es.submit(c);
Future<Singleton_6> f2 = es.submit(c);
Singleton_6 s6 = f1.get();
Singleton_6 s7 = f2.get();
System.out.println(s6);
System.out.println(s7);
System.out.println(s6==s7);
}
}