天天看點

一篇文章讓你徹底了解Java的單例設計模式

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

單例模式的簡介

我們将一個類在目前程序中隻有一個執行個體的這種模式,稱之為“單例模式”

那麼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;
    }     
}