簡述
設計模式類型有3種(創建型,結構型,行爲型)
以下逐一列出創建型類型的設計模式:
1單例,2原型,3工廠,4抽象工廠,5構建者(創建者)模式。
一、單例模式
單例模式就是在一個jvm中只能創建一個對象;分餓漢式單例模式和懶漢式單例模式。
- 餓漢式是加載類的時候就創建該對象。
- 懶漢式爲用的時候才創建該對象。
適用場景
spring中bean的創建默認單例模式
應用服務器有很多系統參數在服務運行期間不會改變的,可用單例創建。
餓漢式demo
- 餓漢式單例模式,類加載的時候就實例化對象,線程安全。
- 簡單實用,推薦
- 個人認爲 不算嚴重的一個缺點,不管用到與否,類裝載時就完成實例化
/**餓漢式 線程安全,加載類時就創建對象*/
public class Mgr01 {
private static final Mgr01 INSTANCE=new Mgr01();//2 私有靜態化常量來創建對象
private Mgr01(){};//1私有化構造方法
public static Mgr01 getInstance(){
return INSTANCE;
}
public static void main(String[] args) {
Mgr01 m1=Mgr01.getInstance();
Mgr01 m2=Mgr01.getInstance();
System.out.println(m1==m2);
}
}
懶漢式demo
demo1 方法,效率低下,不推薦
- 解決按需初始化,線程安全
- 特點:在方法上加同步代碼塊,效率低
public class Mgr04 {
private static Mgr04 INSTANCE;
private Mgr04(){
}
public static synchronized Mgr04 getInstance(){ //synchronized 鎖定當前對象,加了static 鎖定的是class對象
if(INSTANCE==null){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE=new Mgr04();
}
return INSTANCE;
}
public static void main(String[] args) {
for (int i=0;i<100;i++){
new Thread(()-> System.out.println(getInstance().hashCode())).start();
}
}
}
以下爲3種較好的懶漢式單例實現demo,用到時才實例化
2 雙重檢查,即在同步塊前後分別加實例判空邏輯
- spring容器中註冊bean的獲取,就是採用雙重檢查懶加載的單例模式;
- 傳統懶漢式單例中,被認爲是最好的懶漢式單例**<後面還有兩個不錯的單例>**
/**懶漢式
* 滿足按需初始化,滿足線程安全
* 較好1
* */
public class Mgr06 {
private static volatile Mgr06 INSTANCE;//JIT
private Mgr06(){}
public static Mgr06 getInstance(){
if(null==INSTANCE){
synchronized (Mgr06.class){
if(null==INSTANCE){//雙重檢查
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE=new Mgr06();
}
}
}
return INSTANCE;
}
public static void main(String[] args) {
for(int i=1;i<100;i++){
new Thread(()-> System.out.println(getInstance().hashCode())).start();
}
}
}
3 運用虛擬機類加載知識,懶漢式:靜態內部類方式
- 滿足按需初始化,且線程安全
- jvm保證單例,加載外部類時不加載私有靜態內部類,可以實現懶加載
public class Mgr07 {
private Mgr07(){}
private static class Mgr07Holder {
private static final Mgr07 INSTANCE=new Mgr07();
}
public static Mgr07 getInstance(){
return Mgr07Holder.INSTANCE;
}
public static void main(String[] args) {
new Thread(()-> System.out.println(getInstance().hashCode())).start();
}
}
4 解決線程同步,且能防止反序列化(因爲枚舉類沒有構造方法)
- 源自effective java 是java原作者寫的一本書
- 最優單例,可防止反序列化,線程安全
- 餓漢式單例
public enum Mgr08 {
INSTANCE;
public static void main(String[] args) {
for (int i=1;i<100;i++){
new Thread(()-> System.out.println(Mgr08.INSTANCE.hashCode())).start();
}
}
}