91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么實現Java單例模式

發布時間:2021-11-17 09:31:07 來源:億速云 閱讀:188 作者:iii 欄目:大數據

本篇內容主要講解“怎么實現Java單例模式”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“怎么實現Java單例模式”吧!

介紹

單例模式(Singleton Pattern)是一個比較簡單的設計模式,屬于創建型模式。其定義為

確保某一個類只有一個實例,而且自行實例化并向整個系統提供這個實例

在系統中,單例模式要求一個單例對象只能有一個實例,這類對象如果有多個實例就可能會產生一些問題,如:資源消耗過多,處理結果不一致等,一般單例會有以下使用場景

  • 生成唯一 序列號

  • 整個項目的共享訪問點或共享數據,如Web頁面計數器

  • 創建一個對象實例需要消耗過多資源,如I/O和數據庫連接等

在Java中,一個單例對象在一個JVM中,只會有一個實例存在。以下是單例模式結構圖

怎么實現Java單例模式

  • 有一個該單例對象的靜態成員變量

  • 私有的構造函數,只能被自身實例化

  • 提供一個靜態公共方法實例化對象,并訪問該對象實例

單例模式實現

單例模式有兩種實現方式:

  • 餓漢式

  • 懶漢式(延遲加載)

餓漢式

/**
 * 餓漢式單例
 */
public class Singleton1 {
    // 靜態成員變量,在靜態初始化時便實例化對象
    private static final Singleton1 singleton = new Singleton1();
    // 構造私有
    private Singleton1(){
    }
    public static Singleton1 getSingletonInstance(){
        return singleton;
    }
}

餓漢式指的是,在類加載的時候便實例化了該單例對象,不管有沒有使用,先創建了再說。這種方式是可以保證線程安全的,但是如果該對象一直沒有被使用,就浪費了空間資源。

但是對于一些空間占用較大、或是只在某些特定場景才使用的單例,我們會想要在第一次使用的時候才去實例化,這時,就需要懶漢式的延遲加載

懶漢式

/**
 * 懶漢式單例(非線程安全)
 */
public class Singleton2 {
    private static Singleton2 singleton;
    private Singleton2(){}
    // 獲取實例
    public static Singleton2 getSingletonInstance(){
        if(singleton == null){
            singleton =  new Singleton2();
        }
        return singleton;
    }
}

從上面代碼可以看出,懶漢式餓漢式在于單例對象的創建時機。餓漢式是在類加載時便實例化對象,調用時無須判斷直接返回即可;而懶漢式是在第一次調用時實例化,并且每次調用都需要判斷是否已經實例化

但是上面的這種方式在多線程下是不安全的,多個線程同時訪問getSingletonInstance()時,可能會創建多個實例,便不再是單例了。那怎么解決線程安全的問題呢?首先我們可能會想到對getSingletonInstance()方法加上synchronized關鍵字

/**
 * 懶漢式單例(synchronized關鍵字線程安全)
 */
public class Singleton3 {
    private static Singleton3 singleton;
    private Singleton3(){}
    // 獲取實例
    public static synchronized Singleton3 getSingletonInstance(){
        if(singleton == null){
            singleton =  new Singleton3();
        }
        return singleton;
    }
}

getSingletonInstance()方法加上了同步鎖,增加了獲取實例的時間消耗,且在多線程下可能會發生阻塞。但其實我們并不想每次獲取實例的時候都去加上鎖,只是想在第一次調用創建對象時保證線程安全即可

雙重校驗鎖(DCL)

getSingletonInstance()方法加上鎖,確實能保證線程安全,卻存在性能的問題。是不是要必要對整個方法加鎖?還是當我檢查到實例還沒有創建,才去同步

**雙重校驗鎖(double-checked locking,DCL)**是能解決這個問題的

/**
 * 雙重校驗鎖(double-checked locking,DCL)
 */
public class Singleton4 {
     /**
     * 成員變量這里會加上關鍵字 volatile,目的是為了防止指令重排序
     */
    private static volatile Singleton4 singleton;
    private Singleton4(){}
    // 獲取實例
    public static Singleton4 getSingletonInstance(){
        // 第一次校驗,沒有實例化才進入同步代碼塊
        if(singleton == null){
            synchronized (Singleton4.class){
                // 進入同步代碼塊后,再判斷,如果為空才創建實例
                if(singleton == null){
                    singleton =  new Singleton4();
                }
            }
        }
        return singleton;
    }
}

不對方法加上鎖,只對創建實例的代碼加鎖即可。方法中會有兩次判空的操作,第一次是為了不必要的同步,為null才進入同步代碼塊,第二次是進入同步代碼塊后判斷為null才創建實例

注意:這里的成員變量加上了volatile關鍵字

使用volatile可以保證數據的可見性,不過synchronized也是能保證同步數據的可見性的,這里使用volatile更多的目的是為了禁止Java指令重排序

靜態內部類

/**
 * 靜態內部類
 */
public class Singleton5 {
    private Singleton5(){}

    // 獲取實例
    public static Singleton5 getSingletonInstance(){
        return SingletonHolder.SINGLETON;
    }

    /**
     * 內部類,JVM在類加載的時候,是互斥的,可以保證線程安全
     */
    private static class SingletonHolder{
        private static final Singleton5 SINGLETON = new Singleton5();
    }
}

JVM在類加載的時候是會保證數據同步的,我們可以通過內部類來創建單例對象。第一次加載Singleton5時并不會加載內部類,不去使用內部類的時候,該內部類就不會加載。只有第一次調用getSingletonInstance()方法,會去加載內部類并實例化單例對象,這樣就可以做到延遲加載和線程安全了

枚舉方式

使用枚舉方式來實現單例是非常簡潔的,支持序列化機制,絕對防止多次實例化

/**
 * 枚舉方式
 */
public enum Singleton6 {

    /**
     * 枚舉方式實現單例
     */
    SINGLETON;

    public void handle() {
        // to do something
    }
}

該單例的使用方法

public class SingletonDemo {

    @Test
    public void test(){
        // 枚舉方式
        Singleton6 singleton = Singleton6.SINGLETON;
        singleton.handle();
    }
}

到此,相信大家對“怎么實現Java單例模式”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

扬中市| 潢川县| 陆良县| 团风县| 东兴市| 隆回县| 苍山县| 封开县| 林西县| 曲周县| 腾冲县| 枣阳市| 将乐县| 麦盖提县| 临邑县| 大埔区| 阳朔县| 临西县| 汶上县| 江安县| 乌鲁木齐市| 渑池县| 双柏县| 任丘市| 锡林浩特市| 水城县| 天柱县| 平塘县| 蓬溪县| 吉首市| 阳新县| 枣阳市| 连城县| 乌拉特中旗| 辉南县| 昌平区| 米林县| 鸡西市| 志丹县| 龙门县| 商南县|