1. 程式人生 > 遊戲 >《伊甸之路》續作《伊甸決鬥者》上架Steam 2022年發售

《伊甸之路》續作《伊甸決鬥者》上架Steam 2022年發售

介紹

單例(Singleton Pattern)是設計模式中最簡單的一種。屬於建立型模式。它提供了一種建立物件的最佳方式,即記憶體中只有一個例項。也就是不會有人使用 new Singleton()來生成一個新的物件。

意圖

保證一個類僅有一個例項,並提供一個訪問它的全域性方法。

解決

一個全域性使用的類頻繁的建立與銷燬。

優點

  1. 記憶體中只有 一個例項,減少了記憶體開銷,避免了頻繁的建立及銷燬例項;

  2. 避免對資源的多重佔用(寫檔案操作);

缺點

沒有介面,不能繼承,與單一原則衝突,一個類應該只關心內部邏輯,而不關係外部怎樣例項化。

使用場景

  1. 系統產生唯一序列號;

  2. WEB中的計數器,不用每次重新整理在資料庫中加一次,使用單例先快取起來;

UML

示例

  1. 最常用的一種,也是最簡單的一種

    餓漢模式:(推薦)

    /*
     * 功能描述:
     * 〈餓漢式單例模式
     * 類載入到記憶體後,就例項化一個單例,JVM保證執行緒安全
     * 簡單實用,推薦使用
     * 缺點:不管用到與否,類裝載時完成例項化。
     * 〉
     *
     * @author : geoary
     * @date : 2019/12/10 21:33
     */
    public class Mgr01 {
        private static final Mgr01 INSTANCE = new Mgr01();
        // 私有的建構函式
        private Mgr01(){
    
        }
    
        // 獲取唯一物件例項
        public static Mgr01 getInstance(){
            return INSTANCE;
        }
    
        public static void main(String[] args) {
            Mgr01 mgr01 = Mgr01.getInstance();
            Mgr01 mgr02 = Mgr01.getInstance();
            System.out.println(mgr01 == mgr02);
        }
    }
    
  2. 懶載入模式1:

    /**
     * 功能描述:
     * 〈懶載入
     *  雖然達到了按需初始化的目的,但是帶來了執行緒不安全問題
     * 〉
     *
     * @author : geoary
     * @date : 2019/12/10 21:53
     */
    public class Mgr03 {
        private static Mgr03 INSTANCE;
    
        private Mgr03() {
    
        }
    
        public static Mgr03 getInstance() {
            if (INSTANCE == null) {
                try {
                    Thread.sleep(1);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                INSTANCE = new Mgr03();
            }
            return INSTANCE;
        }
    
        public static void main(String[] args) {
            for (int i = 0; i < 100; i++) {
                /*new Thread(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println(Mgr03.getInstance().hashCode());
                    }
                }).start();*/
    
                new Thread(() -> System.out.println(Mgr03.getInstance().hashCode())).start();
            }
        }
    }
    
  3. 懶載入模式2:

    /**
     * 功能描述:
     * 〈懶載入
     *  通過 synchronized 解決執行緒問題,但是效率下降
     * 〉
     *
     * @author : geoary
     * @date : 2019/12/10 21:59
     */
    public class Mgr04 {
        private static Mgr04 INSTANCE;
    
        private Mgr04(){
    
        }
        public static synchronized Mgr04 getInstance(){
            if (INSTANCE == null){
                try {
                    Thread.sleep(1);
                }catch (Exception 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(Mgr04.getInstance().hashCode())).start();
            }
        }
    }
    
  4. 靜態內部類

    /**
     * 功能描述:
     * 〈靜態內部類
     *  jvm 保證單例
     * 〉
     *
     * @author : geoary
     * @date : 2019/12/10 22:12
     */
    public class Mgr07 {
        private Mgr07(){
    
        }
        private static class Mgr07Holder{
            private final static Mgr07 INSTANCE = new Mgr07();
        }
    
        public static Mgr07 getInstance(){
            return Mgr07Holder.INSTANCE;
        }
    
        public static void main(String[] args) {
            for (int i=0; i<100; i++){
                new Thread(()-> System.out.println(Mgr07.getInstance().hashCode())).start();
            }
        }
    }
    

    以上提供了幾種實現單例模式的方式,其中最實用的是第一個餓漢模式,雖然會在類裝載的時候完成例項化,但是使用簡單而且執行緒安全。

應用場景demo

  1. 全域性序列生成器

Singleton.java

package cn.geoaryblog.design.cretedg.single;

public class Singleton {
   private static final Singleton INSTANCE = new Singleton();
   private int num = 0;
   private String name = "預設姓名";

   public static Singleton getInstance() {
       return INSTANCE;
   }

   // 獲取序列
   public static int getNextSeq(){
       INSTANCE.num += 1;
       return INSTANCE.num;
   }
}

SingleMain.java

package cn.geoaryblog.design.cretedg.single;

public class SingleMain {
    public static void main(String[] args) {
        // 多個執行緒是否呼叫同一個例項
        for (int i = 0; i < 20; i++) {
            new Thread(() -> {
                System.out.println("執行緒查詢到的序列是:" + Singleton.getNextSeq());
            }).start();
        }
    }
}