1. 程式人生 > 其它 >一篇文章讓你徹底搞懂單例設計模式

一篇文章讓你徹底搞懂單例設計模式

轉自:

http://www.java265.com/JavaCourse/202109/1153.html

下文是筆者編寫的單例模式實現的八種方式,如下所示:

單例模式的簡介

我們將一個類在當前程序中只有一個例項的這種模式,稱之為“單例模式”
那麼Java程式碼如何實現一個單例模式呢?下文將一一到來,如下所示:

單例模式的注意事項:
   1.單例模式在一個程序中只有一個例項
   2.單例類通常由自己建立自身的例項
   3.單例類給其他物件提供的都是同一個例項

測試程式碼

package com.java265.Singleton;

public class Test {

    public static
void main(String[] args) { // TODO Auto-generated method stub System.out.println("------單例模式-----"); //建立100個執行緒進行測試 for(int i=0;i<100;i++) { new Thread(()->{ System.out.println(Single01.getInstance()); }).start(); } } }

單例實現模式1

餓漢式單例模式:
直接使用一個靜態變數,在JVM載入類時,生成一個單例例項 如下

package com.java265.Singleton;

public class Single01 {    
    private static final Single01 INSTANCE = new Single01();

    private Single01() {}
    
    public static  Single01 getInstance () {
        return INSTANCE;
    }
}

使用static靜態程式碼塊生成一個單例類

package com.java265.Singleton;
public class Single02 {
    private static final Single02  INSTANCE;
    
    static {
         INSTANCE = new Single02();
    }
       
    private Single02() {}

    public static Single02 getInstance() {
        return INSTANCE;    
    }
    public void t() {
         System.out.println("Single02 t方法"
                 + "");
    }
}

使用判斷的方式,建立單例模式,
但是此處不是一個執行緒安全的建立方式

package com.java265.Singleton;

/*
 * 這是一個執行緒不安全的建立單例模式的方式
 * 這是一個懶漢式的建立單例模式的方式
 * */
public class Single03 {
    private static Single03 INSTANCE;
    private Single03() {    
    }

    public  static Single03 getInstance() {
         if(INSTANCE ==null)
         {
                // 多個執行緒都會被卡在此處,
                // 當sleep執行完畢後,多個執行緒會同時建立例項,此處的程式碼是產生執行緒不安全的根源
             try
             {
              Thread.sleep(100);
             }catch(InterruptedException e)
             {
                 
             }
             INSTANCE = new Single03();
         }
         
         return INSTANCE;
    }    
}

使用 synchronized為方法加上鎖,使其執行緒安全

package com.java265.Singleton;
public class Single04 {
    private static volatile Single04 INSTANCE;
    private Single04() {    
    }

    /*
     * 懶漢式生成單例例項 此處使用 synchronized 安全鎖
     */
    public  static  synchronized Single04 getInstance() {
         if(INSTANCE ==null)
         {
             try
             {
              Thread.sleep(100);
             }catch(InterruptedException e)
             {
                 
             }
             INSTANCE = new Single04();
         }
         
         return INSTANCE;
    }    
}

減少鎖粒度,將synchronized關鍵字直接加在方法內部具體的位置上

package com.java265.Singleton;
public class Single05 {

    private static Single05 INSTANCE;
    private Single05() {
        
    }
    public  static   Single05 getInstance() {
         if(INSTANCE ==null)
         {
                /*
                 * 將鎖直接加到方法體裡面 此時出現了一個新的問題 當所有的執行緒都堵塞在此處,也會建立多個例項
                 */
             synchronized(Single05.class) {
             try
             {
              Thread.sleep(100);
             }catch(InterruptedException e)
             {
                 
             }
             INSTANCE = new Single05();
             }
         }     
         return INSTANCE;
    }    
}

將synchronized鎖放入在方法體中,同時使用雙重檢查,避免建立多個例項

package com.java265.Singleton;

public class Single06 {

    private static Single06 INSTANCE;
    private Single06() {
        
    }

    public  static   Single06 getInstance() {
         if(INSTANCE ==null)
         {
             synchronized(Single06.class) {
             try
             {
              Thread.sleep(100);
             }catch(InterruptedException e)
             {
                 
             }
             if(INSTANCE == null)
             {
             INSTANCE = new Single06();
             }
             }
         }
         
         return INSTANCE;
    }    
}

使用靜態內部類的方式建立一個單例物件
此方式主要藉助JVM載入類時,內部類不會被載入
當我們使用內部類的時,才會被載入,此時由JVM保證靜態內部類的唯一性

package com.java265.Singleton;

/*
 * 採用內部類的方式實現一個單例模式
 * */
public class Single07 {

    private Single07() {
        
    }

    private static class Single07Holder {
        private final static Single07 INSTANCE = new Single07();
    }

    public  static   Single07 getInstance() {
        return Single07Holder.INSTANCE;
    }    
}

使用列舉建立一個靜態內部類

package com.java265.Singleton;

/*
 * 採用列舉實現一個單例模式
 * */
public enum Single08 {

    INSTANCE;

    public static Single08 getInstance() {
        return INSTANCE;
    }     
}