免费在线a视频-免费在线观看a视频-免费在线观看大片影视大全-免费在线观看的视频-色播丁香-色播基地

女朋友:你能給我講講單例模式嗎?

:2020年01月01日 腳本之家
分享到:

某公司老板在招程序員時承諾幫助解決單身問題,給程序員分配一個女朋友,于是單身的小強毫不猶豫就去應(yīng)聘了,并被順利錄用。那么我們怎么用代碼來模擬一下呢?首先定義一個女朋友的類,擁有兩個屬性,姓...

本文經(jīng)授權(quán)轉(zhuǎn)自公眾號 程序員修煉(ID:lixing2457)

作者:靜幽水 

如若轉(zhuǎn)載請聯(lián)系原公眾號

01

問題背景

某公司老板在招程序員時承諾幫助解決單身問題,給程序員分配一個女朋友,于是單身的小強毫不猶豫就去應(yīng)聘了,并被順利錄用。那么我們怎么用代碼來模擬一下呢?首先定義一個女朋友的類,擁有兩個屬性,姓名和年齡:

public class GirlFriend {

private String name;

private Integer age;

public GirlFriend(String name, Integer age) {

this.name = name;

this.age = age;

    }

public String getName() {

return name;

    }

public void setName(String name) {

this.name = name;

    }

public Integer getAge() {

return age;

    }

public void setAge(Integer age) {

this.age = age;

    }

@Override

public String toString() {

return "GirlFriend{" +

"name='" + name + '\'' +

", age=" + age +

'}';

    }

}

接著程序員小強就可以new出來一個女朋友的實例了,只需要傳進去姓名和年齡就可以了,如下:

public class Programmer {

public static void main(String[] args){

        GirlFriend girlFriend = new GirlFriend("小美",20);

        System.out.println(girlFriend.toString());

    }

}

打印出的結(jié)果是GirlFriend{name='小美', age=20}

02

有何問題

突然有一天,程序員小強已經(jīng)不滿足只有一個女朋友了,于是他私自new出了多個女朋友對象出來,如下:

public class Programmer {

public static void main(String[] args){

        GirlFriend girlFriend = new GirlFriend("小美",20);

        GirlFriend girlFriend2 = new GirlFriend("小紅",18);

        GirlFriend girlFriend3 = new GirlFriend("小麗",19);

        System.out.println(girlFriend.toString());

        System.out.println(girlFriend2.toString());

        System.out.println(girlFriend3.toString());

    }

}

打印結(jié)果如下:

GirlFriend{name='小美', age=20}

GirlFriend{name='小紅', age=18}

GirlFriend{name='小麗', age=19}

但是不久就被老板發(fā)現(xiàn)了,因為內(nèi)存中存在多個女朋友實例對象,嚴重浪費了公司的資源,老板決定只能給小強分配一個女朋友,老板絞盡腦汁,終于想出了應(yīng)對方法。

03

解決方法

老板發(fā)現(xiàn),問題的根源就是不能把創(chuàng)造女朋友的權(quán)限交給小強,應(yīng)該給他一個創(chuàng)造好的對象,并且姓名和年齡也不能由小強來決定,不然他肯定只要18歲的。而是要把創(chuàng)建實例的權(quán)限收回,讓類自身負責自己類實例的創(chuàng)建。

來看看代碼如何實現(xiàn):

public class GirlFriend {

private String name;

private Integer age;

//定義一個變量來存儲創(chuàng)建好的類實例

private static GirlFriend girlFriend = null;

//私有化構(gòu)造方法,防止外部調(diào)用

private GirlFriend(String name, Integer age) {

this.name = name;

this.age = age;

    }

//定義一個方法為程序員類提供女朋友實例

public static GirlFriend getGirlFriend(){

//判斷存儲實例是否為空

if(girlFriend==null){

//如果沒值,就new出一個實例,并賦值給存儲實例的變量

          girlFriend = new GirlFriend("小美",28);

      }

return girlFriend;

    }

public String getName() {

return name;

    }

public void setName(String name) {

this.name = name;

    }

public Integer getAge() {

return age;

    }

public void setAge(Integer age) {

this.age = age;

    }

@Override

public String toString() {

return "GirlFriend{" +

"name='" + name + '\'' +

", age=" + age +

'}';

    }

}

主要的核心思想有三點:

1.定義一個變量來存儲創(chuàng)建好的類實例;

2.私有化構(gòu)造函數(shù),防止外部new該對象;

3.對外提供一個能獲取到該對象的方法。

程序員小強該如何獲取呢:

public class Programmer {

public static void main(String[] args){

       GirlFriend girlFriend = GirlFriend.getGirlFriend();

        System.out.println(girlFriend.toString());

    }

}

直接使用GirlFriend類調(diào)用獲取對象的getGirlFriend方法獲取到實例對象,打印結(jié)果如下:

GirlFriend{name='小美', age=28}

04

模式講解

上面這種解決方案就是單例模式(Singleton),單例模式定義:保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。

通用類圖如下:

Singleton:負責創(chuàng)建單例類自己的唯一實例,并提供一個getInstance的方法讓外部來訪問這個類的唯一實例。

單例模式功能:保證類在運行期間只允許被創(chuàng)建一個實例。有懶漢式和餓漢式兩種實現(xiàn)方式。

懶漢式:上面的代碼就是懶漢式的實現(xiàn)方式,顧名思義,懶漢式指只有當該實例被使用到的時候才會創(chuàng)建,通過三個步驟就可以實現(xiàn)懶漢式:

1.私有化構(gòu)造方法:防止外部使用。

2.提供獲取實例的方法:全局唯一的類實例訪問點。

3.把獲取實例的方法改為靜態(tài):因為只有靜態(tài)的方法才能直接通過類名來調(diào)用,否則就要通過實例調(diào)用,這就陷入了死循環(huán)。

完整代碼:

public class Singleton{

//定義變量存放創(chuàng)建好的實例,因為要在靜態(tài)方法中使用,所以變量也必須是靜態(tài)的

private static Singleton uniqueInstance = null;

//私有化構(gòu)造方法,可以在內(nèi)部控制創(chuàng)建實例的數(shù)目

private Singleton(){

    }

//定義一個方法為客戶端提供類實例,synchronized同步保證線程安全

public static synchronized Singleton getInstance(){

//判斷是否已經(jīng)有實例

if(uniqueInstance == null){

            uniqueInstance = new Singleton();

        }

//有就直接用

return uniqueInstance;

    }

}

這里使用到了synchronized用來保證線程安全,如果不加會帶來什么問題呢?比如兩個線程A和B,就有可能導(dǎo)致并發(fā)的問題,如圖所示:

這種情況就會創(chuàng)建出兩個實例出來,單例模式也就失效了。加上synchronized雖然能保證線程安全,但是卻降低了訪問速度,影響了性能,可以考慮使用雙重檢查加鎖來解決這個問題,雙重檢查加鎖意思是并不是每次進入getInstance方法都需要同步,而是先不同步,進入方法之后先檢查實例是否存在,如果不存在才進入同步塊。這是第一重檢查。進入同步塊之后再檢查實例是否存在,如果不存在,就在同步的情況下創(chuàng)建一個實例,這是第二重檢查。

代碼實現(xiàn):

public class Singleton{

//對保存實例的變量添加volatile修飾

private volatile static Singleton instance = null;

private Singleton(){

    }

public static Singleton getInstance(){

//第一次檢查

if(instance == null){

//同步塊,線程安全的創(chuàng)建實例

synchronized (Singleton.class){

//第二次檢查

if(instance==null){

                    instance = new Singleton();

                }

            }

        }

return instance;

    }

}

這種方式即可以安全的創(chuàng)建線程,又不會對性能造成太大的影響。

餓漢式:所謂餓漢式也就是在類加載的時候直接new出一個對象來,不管以后用不用得到,是一種以空間換取時間的策略。代碼也非常簡單:

public class Singleton{

//定義一個變量來存儲創(chuàng)建好的實例,直接在這里創(chuàng)建實例,只能創(chuàng)建一次

//static變量在類加載時進行初始化,并且只被初始化一次。

private static Singleton uniqueInstance = new Singleton();

//私有化構(gòu)造方法,可以在內(nèi)部控制創(chuàng)建實例的數(shù)目,防止在外部創(chuàng)建

private Siingleton(){

    }

//定義一個方法為客戶端提供類實例,方法上加static將該方法變?yōu)殪o態(tài)

//目的是不需要對象實例就可以在外部直接通過類來調(diào)用

public static Singleton getInstance(){

//直接使用已經(jīng)創(chuàng)建好的實例

return uniqueInstance;

    }

}

單例模式作用范圍:目前Java里面實現(xiàn)的單例是一個虛擬機的范圍,虛擬機在通過自己的`ClassLoader`裝載餓漢式實現(xiàn)的單例類時就會創(chuàng)建一個類實例。如果一個虛擬機中有多個類加載器或者一個機器中有多個虛擬機,那么單例就不再起作用了。

單例模式優(yōu)缺點:

1.節(jié)約內(nèi)存資源;

2.時間和空間:懶漢式是以時間換空間,餓漢式是以空間換時間;

3.線程安全:不加同步synchronized的懶漢式是線程不安全的,而餓漢式是線程安全的,因為虛擬機只會裝載一次,并且在裝載的時候是不會發(fā)生并發(fā)的。加上synchronized和雙重檢查加鎖也能保證懶漢式的線程安全。

05

新的問題

由于小強工作很賣命,公司業(yè)績發(fā)展的不錯,老板決定再招一名程序員,應(yīng)聘者小華也是一個單身漢,老板也承諾會給他分配女朋友,單是問題來了,之前的GirlFriend只能new出一個對象,總不能讓小強和小華共用一個對象吧。于是要想辦法實現(xiàn)一個可以提供兩個實例的GirlFriend類。

其實思路很簡單,只需要通過Map來緩存實例即可,代碼如下:

import java.util.HashMap;

import java.util.Map;

public class GirlFriend {

private String name;

private Integer age;

private static int maxNumsOfGirlFriends = 2;//最大數(shù)量

private static int number = 1;//當前編號

//定義一個變量來存儲創(chuàng)建好的類實例

private static Map girlFriendMap = new HashMap();

//私有化構(gòu)造方法,防止外部調(diào)用

private GirlFriend(String name, Integer age) {

this.name = name;

this.age = age;

    }

//定義一個方法為程序員類提供女朋友實例

public static GirlFriend getGirlFriend(){

        GirlFriend girlFriend = girlFriendMap.get(number+"");

if(girlFriend==null){

//new一個新實例,并放到map中,用number當做key,實例是value

          girlFriend = new GirlFriend("小美",28);

          girlFriendMap.put(number+"",girlFriend);

        }

        number++;

if(number>maxNumsOfGirlFriends){

            number = 1;

        }

return girlFriend;

    }

public String getName() {

return name;

    }

public void setName(String name) {

this.name = name;

    }

public Integer getAge() {

return age;

    }

public void setAge(Integer age) {

this.age = age;

    }

}

程序員類進行獲取女朋友實例,如下:

public class Programmer {

public static void main(String[] args){

       GirlFriend girlFriend1 = GirlFriend.getGirlFriend();

        System.out.println(girlFriend1);

        GirlFriend girlFriend2 = GirlFriend.getGirlFriend();

        System.out.println(girlFriend2);

        GirlFriend girlFriend3 = GirlFriend.getGirlFriend();

        System.out.println(girlFriend3);

        GirlFriend girlFriend4 = GirlFriend.getGirlFriend();

        System.out.println(girlFriend4);

    }

}

上面代碼獲取了四次,看看打印的結(jié)果如何:

GirlFriend@6e0be858

GirlFriend@61bbe9ba

GirlFriend@6e0be858

GirlFriend@61bbe9ba

可以看出,第一次和第三次是一樣的,第二次和第四次是一樣的,一共就只有兩個對象,解決了這個問題。但是如何判斷哪個女朋友實例是小強的哪個是小華的呢?一種簡單的方法是通過給獲取實例的函數(shù)getGirlFriend傳參,比如小強獲取的時候傳如number = 1,小華的number = 2。

06

相關(guān)擴展

在Java中還用一種更好的單例實現(xiàn)方式,既能夠?qū)崿F(xiàn)延遲加載,又能夠?qū)崿F(xiàn)線程安全。這種解決方案被稱為Lazy initialization holder class模式,這個模式綜合使用了Java的類級內(nèi)部類和多線程缺省同步鎖的知識,很巧妙地同時實現(xiàn)了延遲加載和線程安全。

類級內(nèi)部類:

1.類級內(nèi)部類指的是有static修飾的成員式內(nèi)部類。如果沒有static修飾的成員式內(nèi)部類被稱為對象級內(nèi)部類。

2.類級內(nèi)部類相當于其外部類的static成分,它的對象與外部類對象間不存在依賴關(guān)系,因此可以直接創(chuàng)建。

3.類級內(nèi)部類中可以定義靜態(tài)方法。在靜態(tài)方法中能夠引用外部類中的靜態(tài)成員方法或者成員變量。

4.類級內(nèi)部類相當于其外部類的成員,只有在第一次被使用的時候才會被裝載。

缺省同步鎖:在某些情況下,JVM已經(jīng)隱含地執(zhí)行了同步,不需要自己進行同步控制了,這些情況包括:

1.由靜態(tài)初始化器初始化數(shù)據(jù)時。

2.訪問final字段時

3.在創(chuàng)建線程之前創(chuàng)建對象時

4.線程可以看見它將要處理的對象時。

思路:使用靜態(tài)初始化器的方式,由jvm保證線程安全。但是這樣就像餓漢式的實現(xiàn)方式了,浪費一定的空間。采用類級內(nèi)部類,在這個類級內(nèi)部類里面創(chuàng)建對象實例,只要不使用這個類級內(nèi)部類,就不會創(chuàng)建實例對象。

代碼:

public class Singleton{

//類級內(nèi)部類,該內(nèi)部類的實例與外部類的實例沒有綁定關(guān)系,

// 而且只有被調(diào)用到時才會裝載,從而實現(xiàn)延遲加載

private static class SingletonHolder{

//靜態(tài)初始化器,由jvm保證線程安全

private static Singleton instance = new Singleton();

    }

private Singleton(){

    }

public static Singleton getInstance(){

return SingletonHolder.instance;

    }

}

當getInstance方法第一次被調(diào)用的時候,它第一次讀取 SingletonHolder.instance導(dǎo)致SingletonHolder類得到初始化,從而創(chuàng)建Singleton實例。

枚舉實現(xiàn)單例:

1.Java的枚舉類型實質(zhì)上是功能齊全的類,因此可以有自己的屬性和方法。

2.Java枚舉類型的基本思想是通過共有的靜態(tài)fianl域為每個枚舉常量導(dǎo)出實例的類。

3.從某種角度將,枚舉是單例的泛型化,本質(zhì)上是單元素的枚舉。

代碼:

public enum Singleton{

    uniqueInstance;

//單例自己的操作函數(shù)

public void singletonOperation(){

//功能處理

    }

}

使用枚舉來實現(xiàn)單例控制更加簡潔,而且無償?shù)靥峁┝诵蛄谢臋C制,并由JVM從根本上提供保障,絕對防止多次實例化。

在Spring中,每個Bean默認就是單例的,這樣的優(yōu)點是Spring容器可以管理這些Bean的生命周期,決定什么時候創(chuàng)建出來,什么時候銷毀,銷毀的時候如何處理等等。

使用單例模式需要注意的就是JVM的垃圾回收機制,如果我們的一個單例對象在內(nèi)存中長久不使用,JVM就認為這個對象是一個垃圾,在CPU資源空閑的情況下該對象會被清理掉,下次再調(diào)用時就需要重新產(chǎn)生一個對象。

[我要糾錯]
文:王振袢&發(fā)表于江蘇
關(guān)鍵詞: 本文 授權(quán) 轉(zhuǎn)自 公眾 單例模式

來源:本文內(nèi)容搜集或轉(zhuǎn)自各大網(wǎng)絡(luò)平臺,并已注明來源、出處,如果轉(zhuǎn)載侵犯您的版權(quán)或非授權(quán)發(fā)布,請聯(lián)系小編,我們會及時審核處理。
聲明:江蘇教育黃頁對文中觀點保持中立,對所包含內(nèi)容的準確性、可靠性或者完整性不提供任何明示或暗示的保證,不對文章觀點負責,僅作分享之用,文章版權(quán)及插圖屬于原作者。

點個贊
0
踩一腳
0

您在閱讀:女朋友:你能給我講講單例模式嗎?

Copyright?2013-2024 JSedu114 All Rights Reserved. 江蘇教育信息綜合發(fā)布查詢平臺保留所有權(quán)利

蘇公網(wǎng)安備32010402000125 蘇ICP備14051488號-3技術(shù)支持:南京博盛藍睿網(wǎng)絡(luò)科技有限公司

南京思必達教育科技有限公司版權(quán)所有   百度統(tǒng)計

主站蜘蛛池模板: 天天爽天天操 | 欧美一级日韩 | 深夜在线影院 | 污污网站免费入口链接 | 一级女性黄 色生活片 | 亚洲国产成人综合精品2020 | 成年男女免费视频网站 | 欧美亚洲国产人成aaa | 久久精品免费观看 | 亚洲人成在线免费观看 | 人人添人人澡人人澡人人诱 | 成人毛片在线 | 欧美日本成人 | 日韩高清在线日韩大片观看网址 | 正品蓝导航永久福利在线视频 | 亚洲黄视频在线观看 | 波多在线视频 | 日产免费自线一二 | 99视频有精品视频免费观看 | 免费看的黄色大片 | a久久久久一级毛片护士免费 | 曰批免费视频播放免费完整 | 一级理论片免费观看在线 | 日韩区欧美区 | 丁香六月欧美 | 天天拍夜夜添久久精品中文 | 免费的涩涩视频 | 亚洲欧洲在线视频 | 一二三四视频社区在线播放中国 | 欧美双茎同入视频在线观看 | 一级特级全黄 | 亚洲欧美一区二区三区四区 | 日韩欧美第一页 | 日本欧美不卡一区二区三区在线 | 日韩亚洲欧洲在线com91tv | 伦理影院在线 | 簧片在线 | 国产一级视频播放 | 男女黄网站 | 午夜精品国产爱在线观看不卡 | 首页 动漫 亚洲 欧美 日韩 |
最熱文章
最新文章
  • 阿里云上云鉅惠,云產(chǎn)品享最低成本,有需要聯(lián)系,
  • 卡爾蔡司鏡片優(yōu)惠店,鏡片價格低
  • 蘋果原裝手機殼