最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java單例模式的創(chuàng)建,破壞和防破壞詳解

 更新時(shí)間:2021年09月08日 08:59:52   作者:牛哄哄的柯南  
大家所熟知的單例模式只能創(chuàng)建唯一一個(gè)實(shí)例,今天我們介紹幾種常見的單例模式,同時(shí)說一說如何破壞單例模式,同時(shí)又怎么來防破壞

前言

大家所熟知的單例模式只能創(chuàng)建唯一一個(gè)實(shí)例,今天我們介紹幾種常見的單例模式,同時(shí)說一說如何破壞單例模式,同時(shí)又怎么來防破壞。

單例模式

單例模式(Singleton Pattern)是 Java 中最簡單的設(shè)計(jì)模式之一。這種類型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對象的最佳方式。

這種模式涉及到一個(gè)單一的類,該類負(fù)責(zé)創(chuàng)建自己的對象,同時(shí)確保只有單個(gè)對象被創(chuàng)建。這個(gè)類提供了一種訪問其唯一的對象的方式,可以直接訪問,不需要實(shí)例化該類的對象。

1、單例類只能有一個(gè)實(shí)例。

2、單例類必須自己創(chuàng)建自己的唯一實(shí)例。

3、單例類必須給所有其他對象提供這一實(shí)例。

單例模式的幾種實(shí)現(xiàn)方式

懶漢式,線程不安全

下面的懶漢式是線程不安全的,支持懶加載,因?yàn)闆]有加鎖 synchronized,所以嚴(yán)格意義上它并不算單例模式。

樣例代碼:

public class Singleton{
	private static Singleton instance;
	private Singleton(){
	}
	public static Singleton getInstance(){
	    if(instance == null){
	        return new Singleton();
	    }
	    return instance;
	}
}

懶漢式,線程安全

下面的這種方式可以保證線程安全,支持懶加載,優(yōu)點(diǎn)是第一次調(diào)用才初始化,避免內(nèi)存浪費(fèi)。缺點(diǎn)是必須加鎖synchronized 才能保證單例,但加鎖會(huì)影響效率。

樣例代碼:

public class Singleton{
	private static Singleton instance;
	private Singleton(){
	}
	public static synchronized Singleton getInstance(){
	    if(instance == null){
	        return new Singleton();
	    }
	    return instance;
	}
}

餓漢式

餓漢式,比較常用,但是容易參生垃圾對象,這種方式不支持懶加載,線程安全,優(yōu)點(diǎn)是沒有加鎖,執(zhí)行效率會(huì)提高。缺點(diǎn)是類加載時(shí)就初始化,浪費(fèi)內(nèi)存。

樣例代碼:

public class Singleton {  
    private static Singleton instance = new Singleton();  
    private Singleton (){
    }  
    public static Singleton getInstance() {  
    	return instance;  
    }  
}

雙檢鎖/雙重校驗(yàn)鎖

這種方式支持懶加載,線程安全,這種方式采用雙鎖機(jī)制,安全且在多線程情況下能保持高性能。

樣例代碼:

public class Singleton {  
    private volatile static Singleton instance;
    private Singleton(){
    }
    public static Singleton getInstance(){
        if(instance==null){
            synchronized (Singleton.class){
                if(instance == null){
                    instance = new Singleton();
                }
            }
        }
        return instance;
    } 
}

登記式/靜態(tài)內(nèi)部類

這種方式支持懶加載,線程安全,這種方式能達(dá)到雙檢鎖方式一樣的功效,但實(shí)現(xiàn)更簡單。對靜態(tài)域使用延遲初始化,應(yīng)使用這種方式而不是雙檢鎖方式。這種方式只適用于靜態(tài)域的情況,雙檢鎖方式可在實(shí)例域需要延遲初始化時(shí)使用。

public class Singleton {  
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
    private  Singleton(){
    }
    public static final Singleton getInstance(){
        return SingletonHolder.INSTANCE;
    }  
}

枚舉

這種實(shí)現(xiàn)方式不支持懶加載,線程安全,不過還沒有被廣泛采用,但這是實(shí)現(xiàn)單例模式的最佳方法。它更簡潔,自動(dòng)支持序列化機(jī)制,絕對防止多次實(shí)例化。這種方式是 Effective Java 作者 Josh Bloch 提倡的方式,它不僅能避免多線程同步問題,而且還自動(dòng)支持序列化機(jī)制,防止反序列化重新創(chuàng)建新的對象,絕對防止多次實(shí)例化。

public enum Singleton {  
    INSTANCE;  
    public void whateverMethod() {  
    }  
}

模擬一個(gè)數(shù)據(jù)庫連接類:

public enum SingletonEnum {
    INSTANCE;
    private DBConnection connection = null;
    SingletonEnum(){
        connection = new DBConnection();
    }
    public DBConnection getConnection(){
        return connection;
    }
}
public class DBConnection{
}
public class TestConnection {
    public static void main(String[] args) {
        DBConnection con1 = DataSourceEnum.DATASOURCE.getConnection();
        DBConnection con2 = DataSourceEnum.DATASOURCE.getConnection();
        System.out.println(con1 == con2); //輸出結(jié)果為true。
    }
}

破壞單例模式

破壞單例模式主要有兩種方法:反射、反序列化

我們就拿最經(jīng)典的餓漢式來演示破壞和防破壞。

未破壞的情況

Singleton:

/**
 * Keafmd
 *
 * @ClassName: Singleton
 * @Description: 單例模式
 * @author: 牛哄哄的柯南
 * @date: 2021-09-07 10:53
 */
public class Singleton {
    private static Singleton instance = new Singleton();
    private Singleton (){
    }
    public static Singleton getInstance() {
        return instance;
    }
}

測試類(未破壞):

/**
 * Keafmd
 *
 * @ClassName: SigletonTest
 * @Description: 測試類
 * @author: 牛哄哄的柯南
 * @date: 2021-09-07 11:04
 */
public class SingletonTest {
    public static void main(String[] args) {
        Singleton instance1 = Singleton.getInstance(); 
        Singleton instance2 = Singleton.getInstance();
        System.out.println(instance1); //com.keafmd.Study.designPatterns.Blog.Singleton@610455d6
        System.out.println(instance2); //com.keafmd.Study.designPatterns.Blog.Singleton@610455d6
        System.out.println(instance1==instance2); //true
    }
}

破壞后的情況

Singleton:(不改變)

/**
 * Keafmd
 *
 * @ClassName: Singleton
 * @Description: 單例模式
 * @author: 牛哄哄的柯南
 * @date: 2021-09-07 10:53
 */
public class Singleton {
    private static Singleton instance = new Singleton();
    private Singleton (){
    }
    public static Singleton getInstance() {
        return instance;
    }
}

測試類(通過反射破壞):

package com.keafmd.Study.designPatterns.Blog;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
 * Keafmd
 *
 * @ClassName: SigletonTest
 * @Description: 測試類
 * @author: 牛哄哄的柯南
 * @date: 2021-09-07 11:04
 */
public class SingletonTest {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Singleton instance1 = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        System.out.println(instance1); //com.keafmd.Study.designPatterns.Blog.Singleton@610455d6
        System.out.println(instance2); //com.keafmd.Study.designPatterns.Blog.Singleton@610455d6
        System.out.println(instance1==instance2); //true
        //=====================破壞單例模式===================
        //通過反射獲取實(shí)例,破壞單例
        Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();
        constructor.setAccessible(true);
        Singleton instance11 = constructor.newInstance();
        Singleton instance22 = constructor.newInstance();
        System.out.println(instance11); //com.keafmd.Study.designPatterns.Blog.Singleton@511d50c0
        System.out.println(instance22); //com.keafmd.Study.designPatterns.Blog.Singleton@60e53b93
        System.out.println(instance11==instance22); //false 證明單例模式已經(jīng)被破壞
    }
}

輸出結(jié)果:

com.keafmd.Study.designPatterns.Blog.Singleton@610455d6
com.keafmd.Study.designPatterns.Blog.Singleton@610455d6
true
com.keafmd.Study.designPatterns.Blog.Singleton@511d50c0
com.keafmd.Study.designPatterns.Blog.Singleton@60e53b93
false

Process finished with exit code 0

這種破壞是通過java的反射機(jī)制,創(chuàng)建一個(gè)實(shí)例,這種破壞方法通過setAccessible(true)的方法是java跳過檢測語法,可以臨時(shí)改變訪問權(quán)限,就可以獲取私有成員變量。

單例模式的防破壞

其實(shí)防止破壞最簡單的一種方式就是判斷下有沒有創(chuàng)建過實(shí)例,如果是第二次創(chuàng)建實(shí)例對象的時(shí)候,直接拋出異常,阻止創(chuàng)建即可。

重寫Singleton類:

package com.keafmd.Study.designPatterns.Blog;
/**
 * Keafmd
 *
 * @ClassName: Singleton
 * @Description: 單例模式
 * @author: 牛哄哄的柯南
 * @date: 2021-09-07 10:53
 */
public class Singleton {
    //阻止實(shí)例化
    private static boolean flag=true;
    private static Singleton instance = new Singleton();
    private Singleton (){
        if(!flag){
            throw new RuntimeException("這個(gè)單例模式類不能創(chuàng)建更多的對象了");
        }
    }
    public static Singleton getInstance() {
        if(flag){
            flag=false; //第一次創(chuàng)建時(shí)就會(huì)改變flag的值,導(dǎo)致后面創(chuàng)建不成功
        }
        return instance;
    }
}

測試類(未改變):

package com.keafmd.Study.designPatterns.Blog;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
 * Keafmd
 *
 * @ClassName: SigletonTest
 * @Description: 測試類
 * @author: 牛哄哄的柯南
 * @date: 2021-09-07 11:04
 */
public class SingletonTest {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Singleton instance1 = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        System.out.println(instance1);
        System.out.println(instance2);
        System.out.println(instance1==instance2);
        //=====================破壞單例模式===================
        //通過反射獲取實(shí)例,破壞單例
        Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();
        constructor.setAccessible(true);
        Singleton instance11 = constructor.newInstance();
        Singleton instance22 = constructor.newInstance();
        System.out.println(instance11);
        System.out.println(instance22);
        System.out.println(instance11==instance22);
    }
}

輸出結(jié)果:

com.keafmd.Study.designPatterns.Blog.Singleton@610455d6
com.keafmd.Study.designPatterns.Blog.Singleton@610455d6
true
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at com.keafmd.Study.designPatterns.Blog.SingletonTest.main(SingletonTest.java:28)
Caused by: java.lang.RuntimeException: 這個(gè)單例模式類不能創(chuàng)建更多的對象了
at com.keafmd.Study.designPatterns.Blog.Singleton.<init>(Singleton.java:28)
... 5 more

Process finished with exit code 1

這樣在執(zhí)行到Singleton instance22 = constructor.newInstance();這行的時(shí)候就會(huì)拋出異常,這樣就防止了破壞。

總結(jié)

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

  • Jpa?Specification如何實(shí)現(xiàn)and和or同時(shí)使用查詢

    Jpa?Specification如何實(shí)現(xiàn)and和or同時(shí)使用查詢

    這篇文章主要介紹了Jpa?Specification如何實(shí)現(xiàn)and和or同時(shí)使用查詢,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • 哲學(xué)家就餐問題中的JAVA多線程學(xué)習(xí)

    哲學(xué)家就餐問題中的JAVA多線程學(xué)習(xí)

    哲學(xué)家就餐問題是1965年由Dijkstra提出的一種線程同步的問題,下面我們就看一下JAVA多線程如何做
    2013-11-11
  • Java中如何執(zhí)行多條shell/bat命令

    Java中如何執(zhí)行多條shell/bat命令

    這篇文章主要介紹了Java中如何執(zhí)行多條shell/bat命令的方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • idea導(dǎo)入項(xiàng)目爆紅問題記錄以及解決

    idea導(dǎo)入項(xiàng)目爆紅問題記錄以及解決

    這篇文章主要介紹了idea導(dǎo)入項(xiàng)目爆紅問題記錄以及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • java簡單實(shí)現(xiàn)斗地主發(fā)牌功能

    java簡單實(shí)現(xiàn)斗地主發(fā)牌功能

    這篇文章主要為大家詳細(xì)介紹了java簡單實(shí)現(xiàn)斗地主發(fā)牌功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • springboot中redis的緩存穿透問題實(shí)現(xiàn)

    springboot中redis的緩存穿透問題實(shí)現(xiàn)

    這篇文章主要介紹了springboot中redis的緩存穿透問題實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • 基于SSM框架實(shí)現(xiàn)簡單的登錄注冊的示例代碼

    基于SSM框架實(shí)現(xiàn)簡單的登錄注冊的示例代碼

    這篇文章主要介紹了基于SSM框架實(shí)現(xiàn)簡單的登錄注冊的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-12-12
  • log4j2的異步使用及添加自定義參數(shù)方式

    log4j2的異步使用及添加自定義參數(shù)方式

    這篇文章主要介紹了log4j2的異步使用及添加自定義參數(shù)方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • 如何使用MyBatis框架實(shí)現(xiàn)增刪改查(CRUD)操作

    如何使用MyBatis框架實(shí)現(xiàn)增刪改查(CRUD)操作

    本文主要介紹了如何使用MyBatis框架實(shí)現(xiàn)增刪改查(CRUD)操作。首先介紹了MyBatis框架的基本概念和使用方法,然后分別介紹了如何使用MyBatis實(shí)現(xiàn)增刪改查操作。最后,通過一個(gè)簡單的示例演示了如何使用MyBatis框架實(shí)現(xiàn)CRUD操作。
    2023-05-05
  • SpringBoot?Security使用MySQL實(shí)現(xiàn)驗(yàn)證與權(quán)限管理

    SpringBoot?Security使用MySQL實(shí)現(xiàn)驗(yàn)證與權(quán)限管理

    安全管理是軟件系統(tǒng)必不可少的的功能。根據(jù)經(jīng)典的“墨菲定律”——凡是可能,總會(huì)發(fā)生。如果系統(tǒng)存在安全隱患,最終必然會(huì)出現(xiàn)問題,這篇文章主要介紹了SpringBoot安全管理Spring?Security基本配置
    2022-11-11

最新評論

唐海县| 克什克腾旗| 曲靖市| 西丰县| 高州市| 韩城市| 原平市| 沛县| 太康县| 鲁甸县| 二手房| 湖南省| 临沂市| 德州市| 印江| 日照市| 平利县| 阜平县| 瓦房店市| 五大连池市| 盖州市| 嘉兴市| 张家口市| 南华县| 崇明县| 宁远县| 文安县| 关岭| 囊谦县| 高碑店市| 弋阳县| 贡觉县| 安多县| 宜宾县| 聂拉木县| 始兴县| 阿克苏市| 永新县| 正镶白旗| 浠水县| 新泰市|