女人久久久,最近更新中文字幕在线,成人国内精品久久久久影院vr,中文字幕亚洲综合久久综合,久久精品秘?一区二区三区美小说

原創(chuàng)生活

國內(nèi) 商業(yè) 滾動(dòng)

基金 金融 股票

期貨金融

科技 行業(yè) 房產(chǎn)

銀行 公司 消費(fèi)

生活滾動(dòng)

保險(xiǎn) 海外 觀察

財(cái)經(jīng) 生活 期貨

當(dāng)前位置:滾動(dòng) >

java單例模式并不難 Java設(shè)計(jì)模式系列演示

文章來源:財(cái)金網(wǎng)  發(fā)布時(shí)間: 2019-04-11 10:00:26  責(zé)任編輯:cfenews.com
+|-

【原標(biāo)題:java單例模式并不難 Java設(shè)計(jì)模式系列演示】為什么單例

1、在內(nèi)存中只有一個(gè)對(duì)象,節(jié)省內(nèi)存空間。避免頻繁的創(chuàng)建銷毀對(duì)象,可以提高性能。避免對(duì)共享資源的多重占用。可以全局訪問。

2、確保一個(gè)類只有一個(gè)實(shí)例,自行實(shí)例化并向系統(tǒng)提供這個(gè)實(shí)例

單例需要注意的問題

1、線程安全問題

2、資源使用問題

實(shí)際上本文就是在討論這兩個(gè)問題

1、餓漢式

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

優(yōu)點(diǎn):

在未調(diào)用getInstance() 之前,實(shí)例就已經(jīng)創(chuàng)建了,天生線程安全

缺點(diǎn):

如果一直沒有調(diào)用getInstance() , 但是已經(jīng)創(chuàng)建了實(shí)例,造成了資源浪費(fèi)。

2、懶漢式

package com;public class Person {    private static Person person ;    private Person(){    }    public static Person get(){        if ( person == null ) {            person = new Person() ;        }        return person ;    }}

優(yōu)點(diǎn):

get() 方法被調(diào)用的時(shí)候,才創(chuàng)建實(shí)例,節(jié)省資源。

缺點(diǎn):

線程不安全。

這種模式,可以做到單例模式,但是只是在單線程中是單例的,如果在多線程中操作,可能出現(xiàn)多個(gè)實(shí)例。

測(cè)試:啟動(dòng)20個(gè)線程,然后在線程中打印 Person 實(shí)例的內(nèi)存地址

package com;public class A1  {    public static void main(String[] args) {        for ( int i = 0 ;  i < 20 ; i ++ ) {            new Thread( new Runnable() {                @Override                public void run() {                    System.out.println( Person.get().hashCode() );                }            }).start(); ;        }    }}

結(jié)果:可以看到出現(xiàn)了兩個(gè) Person 實(shí)例,效果圖如下:

創(chuàng)建兩個(gè)實(shí)例原因分析:

線程A希望使用 Person ,調(diào)用 get()方法。因?yàn)槭堑谝淮握{(diào)用,A 就發(fā)現(xiàn) person 是 null 的,于是它開始創(chuàng)建實(shí)例,就在這個(gè)時(shí)候,CPU 發(fā)生時(shí)間片切換,線程B開始執(zhí)行,它要使用 Person ,調(diào)用get()方法,同樣檢測(cè)到 person 是null ——注意,這是在 A 檢測(cè)完之后切換的,也就是說 A 并沒有來得及創(chuàng)建對(duì)象——因此 B 開始創(chuàng)建。B創(chuàng)建完成后,切換到A繼續(xù)執(zhí)行,因?yàn)樗呀?jīng)檢測(cè)完了,所以A不會(huì)再檢測(cè)一遍,它會(huì)直接創(chuàng)建對(duì)象。這樣,線程 A 和 B 各自擁有一個(gè) Person 的對(duì)象——單例失敗!

總結(jié):

1、可以實(shí)現(xiàn)單線程單例

2、多線單例無法保證

改進(jìn):

1、加鎖

3、 用synchronized 加鎖同步

package com;public class Person {    private static Person person ;    private Person(){    }    public synchronized static Person get(){        if ( person == null ) {            person = new Person() ;        }        return person ;    }}

經(jīng)過測(cè)試,已經(jīng)可以滿足多線程的安全問題了,synchronized 修飾的同步塊可是要比一般的代碼段慢上幾倍的!如果存在很多次 get() 的調(diào)用,那性能問題就不得不考慮了!

優(yōu)點(diǎn):

1、滿足單線程的單例

2、滿足多線程的單例

缺點(diǎn):

1、性能差

4、改進(jìn)性能 雙重校驗(yàn)

package com;public class Person {    private static Person person ;    private Person(){    }    public synchronized static Person get(){        if ( person == null ) {            synchronized ( Person.class ){                if (person == null) {                    person = new Person();                }            }        }        return person ;    }}

首先判斷 person 是不是為 null ,如果為 null ,加鎖初始化;如果不為 null ,直接返回 person 。整個(gè)設(shè)計(jì),進(jìn)行了雙重校驗(yàn)。

優(yōu)點(diǎn):

1、滿足單線程單例

2、滿足多線程單例

3、性能問題得以優(yōu)化

缺點(diǎn):

1、第一次加載時(shí)反應(yīng)不快,由于java內(nèi)存模型一些原因偶爾失敗

5、volatile 關(guān)鍵字,解決雙重校驗(yàn)帶來的弊端

package com;public class Person {    private static volatile Person person = null ;    private Person(){    }    public static Person getInstance(){        if ( person == null ) {            synchronized ( Person.class ){                if ( person == null ) {                    person = new Person() ;                }            }        }        return person ;    }}

假設(shè)沒有關(guān)鍵字 volatile 的情況下,兩個(gè)線程 A、B,都是第一次調(diào)用該單例方法,線程A先執(zhí)行 person = new Person(),該構(gòu)造方法是一個(gè)非原子操作,編譯后生成多條字節(jié)碼指令,由于JAVA的指令重排序,可能會(huì)先執(zhí)行 person 的賦值操作,該操作實(shí)際只是在內(nèi)存中開辟一片存儲(chǔ)對(duì)象的區(qū)域后直接返回內(nèi)存的引用,之后 person 便不為空了,但是實(shí)際的初始化操作卻還沒有執(zhí)行,如果就在此時(shí)線程 B 進(jìn)入,就會(huì)看到一個(gè)不為空的但是不完整 (沒有完成初始化)的 Person 對(duì)象,所以需要加入 volatile 關(guān)鍵字,禁止指令重排序優(yōu)化,從而安全的實(shí)現(xiàn)單例。

補(bǔ)充:看了圖片加載框架 Glide (3.7.0版) 源碼,發(fā)現(xiàn) glide 也是使用 volatile 關(guān)鍵字的雙重校驗(yàn)實(shí)現(xiàn)的單例,可見這種方法是值得信賴的。

6、靜態(tài)內(nèi)部類

package com;public class Person {    private Person(){    }    private static class PersonHolder{        /**         * 靜態(tài)初始化器,由JVM來保證線程安全         */        private static Person instance = new Person();    }    public static Person getInstance() {        return PersonHolder.instance;    }}

優(yōu)點(diǎn):

1、資源利用率高,不執(zhí)行g(shù)etInstance()不被實(shí)例,可以執(zhí)行該類其他靜態(tài)方法

7、枚舉類實(shí)現(xiàn)單例

package com;public enum Singleton {    INSTANCE ;    public void show(){        // Do you need to do things    }}

使用

獲取實(shí)例對(duì)象:Singleton.INSTANCE調(diào)用其他方法:Singleton.INSTANCE.show();

總結(jié):

1、上面的7中方法,都實(shí)現(xiàn)了某種程度的單例,各有利弊,根據(jù)使用的場景不同,需要滿足的特性不同,選取合適的單例方法才是正道。

2、對(duì)線程要求嚴(yán)格,對(duì)資源要求不嚴(yán)格的推薦使用:1 餓漢式

3、對(duì)線程要求不嚴(yán)格,對(duì)資源要求嚴(yán)格的推薦使用:2 懶漢式

4、對(duì)線程要求稍微嚴(yán)格,對(duì)資源要求嚴(yán)格的推薦使用:4 雙重加鎖

5、同時(shí)對(duì)線程、資源要求非常嚴(yán)格的推薦使用:5 、 6

專題首頁|財(cái)金網(wǎng)首頁

原創(chuàng)
新聞

精彩
互動(dòng)

獨(dú)家
觀察

京ICP備2021034106號(hào)-38   營業(yè)執(zhí)照公示信息  財(cái)金網(wǎng)  版權(quán)所有  cfenews.com  投稿郵箱:362293157@qq.com  業(yè)務(wù)QQ:362293157立即發(fā)帖