国产激情自拍_国产9色视频_丁香花在线电影小说观看 _久久久久国产精品嫩草影院

首頁 > 系統(tǒng) > Android > 正文

Android中單例模式的一些坑小結(jié)

2019-10-21 21:25:06
字體:
供稿:網(wǎng)友

前言

單例模式最初的定義出現(xiàn)于《設(shè)計模式》(艾迪生維斯理, 1994):“保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。”

而我對單例的理解是,在可控的范圍內(nèi)充當(dāng)全局變量的作用,就相當(dāng)于C語言中一個全局結(jié)構(gòu)體。

首先來看這樣一個單例,稍微有點經(jīng)驗的同學(xué)可能都會說,這樣的單例是非線程安全的。要加個volatile關(guān)鍵字才可以。

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

但是你要是問他,為什么是非線程安全的單例就答不出來了。搞清楚這個問題其實 對我們的多線程理解是很有好處的。
我們首先明確一下對于jvm來說,完成對一個變量的寫操作 到底是如何進行的。

寫操作:

(1)先把值寫入cpu的高速緩存cache中。(2)然后再把這個cache中的值拷貝到ram(也就是我們的內(nèi)存)中。

注意啊,對于一個寫操作來說,這個(1)(2) 可不是原子操作,很有可能(1)執(zhí)行完畢以后,cpu又去干了其他事情,
并沒有第一時間把cache的值 寫入到ram中。而我們讀操作,都是從ram中去讀取一個值的。

所以這里我們可以想一下,如果是多線程場景的話,會有一些坑。

然后再說一個概念,對于 singleton=new Singleton(); 這一條語句來說,他顯然不是一條指令就可以完成的。

正常情況來說,我們要完成這條語句涉及到的指令大約如下:

1.申請一段堆內(nèi)存空間

2.在這個堆內(nèi)存空間中把我們需要的對象初始化完畢

3.把singleton這個引用指向我們的堆內(nèi)存空間地址。

但是坑爹就坑爹在,虛擬機會有一個指令重排序的概念。當(dāng)虛擬機發(fā)現(xiàn)單線程下 指令的順序變更不會導(dǎo)致結(jié)果異常的時候
就會觸發(fā)指令重排序的機制, 他會導(dǎo)致上述的 123順序發(fā)生變更,比如我們把順序改成132 你就會發(fā)現(xiàn) 結(jié)果還是一樣的。

(指令重排序的觸發(fā)機制準確的來說是happens before原則 有興趣的同學(xué)可以深挖)

如果發(fā)生132的執(zhí)行順序 會發(fā)生什么?

假設(shè)線程a 進入到了同步代碼塊中,這個時候觸發(fā)了指令重排序,順序變成132,假設(shè)cpu這個時候執(zhí)行了13。然后轉(zhuǎn)頭
去執(zhí)行線程b,線程b 進入getInstance方法的時候,他發(fā)現(xiàn)singleton 不是null了,于是歡天喜地的return了,
但是要知道這個時候線程a的 2還沒執(zhí)行,也就是說singleton雖然不是空,但是他指向的地址空間里面啥都沒有,對象還沒有初始化。所以這是一個非常大的隱患,雖然他發(fā)生的概率極低,低到我現(xiàn)在都沒有復(fù)現(xiàn)過這種現(xiàn)象,但是依舊有概率。

那么正確的寫法:

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

有很多人就會說 volatile 這個關(guān)鍵字以后,singleton=new Singleton(); 就不會發(fā)生指令重排了,所以這么做是正確的。

現(xiàn)在明確的告訴你,上面這個觀點是錯誤的

singleton=new Singleton();  這條語句背后的指令依舊有概率發(fā)生指令重排,只不過 volatile修飾過以后,在 這條語句背后的指令完全執(zhí)行完畢以前,對singleton這個引用的讀操作全部被屏蔽了。

也就是說 132的執(zhí)行順序依舊會發(fā)生,只不過 當(dāng)執(zhí)行完13 而2沒有執(zhí)行的時候,volatile修飾過的這個變量,所有對他的讀操作
都會暫時屏蔽,等待2操作執(zhí)行完以后,才會進行讀操作。

這才是volatile關(guān)鍵字加上去以后的作用。

android很多代碼比如eventbus的單例就是用的上述寫法。

當(dāng)然了,上述寫法是典型的懶漢寫法,所謂懶漢你就理解成用的時候才實例化,不用的話不實例化。

但是如果你的需求是這個單例無論在什么情況下都會存在,你當(dāng)然可以寫成餓漢,餓漢的寫法更簡單。

缺點就是他會一直占用內(nèi)存。餓漢寫法很多,我寫個最簡單的:

 class Singleton {  //最簡單的寫法就是這個了,直接public就行  public static final Singleton instance = new Singleton();  private Singleton() {  } }

單例序列化會破壞對象唯一性嗎?

答案是會的:

package com.wuyue.test;import java.io.*;/** * Created by 16040657 on 2019/2/12. */public class Test2 { public static void main(String args[]) {  Singleton s1 = Singleton.instance;  File f = new File("../test.txt");  try {   ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(f));   oos.writeObject(s1);   oos.close();   ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f));   Singleton s3 = (Singleton) ois.readObject();   System.out.println("s1==s3:" + (s1 == s3));  } catch (IOException e) {   e.printStackTrace();  } catch (ClassNotFoundException e) {   e.printStackTrace();  } } static class Singleton implements Serializable {  //最簡單的寫法就是這個了,直接public就行  public static final Singleton instance = new Singleton();  private Singleton() {  }//  //這個方法就可以保證序列化和反序列化得到的對象是同一個了//  private Object readResolve() {//   return instance;//  } }}

代碼比較簡單,大家可以測試一下,s1和s3就是2個不同的對象,但是如果把注釋掉的readResolve方法放開的話,你就會發(fā)現(xiàn)
這個問題解決了,序列化和反序列化是同一個對象了。

對外部公開提供的sdk的單例要注意些什么?

尤其是對于很多金融安全類的sdk來說,如果你這個里面有單例的話,涉及到安全性要盡可能的不被業(yè)務(wù)方hook,
其中尤其要注意的就是 有人可能會利用反射來new一個對象,破壞單例

解決這個問題也不難,

 private Singleton() {   //防止有人利用反射惡意修改   if (null != instance) {    throw new RuntimeException("dont construct more!");   }  }

項目中的單例太多,如何有效管理?

其實就拿map管理就可以了,android里面的 wms,ams 等等系統(tǒng)單例服務(wù)都是這樣的。你傳一個key進去 返回一個單例給你。
這個真的很有用哦,特別是大型工程,可以有效管理單例,文檔輸出就簡單許多。

 static class SingletonManager {  private static Map<String, Object> objectMap = new HashMap<>();  private SingletonManager() {  }  public static void registerService(String key, Object ins) {   if (!objectMap.containsKey(key)) {    objectMap.put(key, ins);   }  }  public static Object getService(String key) {   return objectMap.get(key);  } }

android中使用單例還要注意些什么?

最主要的就是盡量不要利用單例模式存儲傳遞數(shù)據(jù),因為app掛在后臺的時候進程會容易被殺掉,如果回到前臺再取這個單例里的數(shù)據(jù)很容易就取到個null,所以android中寫單例的原則就是:

原則上不允許用單例模式傳遞數(shù)據(jù),如果一定要這么做,請考慮數(shù)據(jù)恢復(fù)現(xiàn)場。

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網(wǎng)的支持。


注:相關(guān)教程知識閱讀請移步到Android開發(fā)頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
国产激情自拍_国产9色视频_丁香花在线电影小说观看 _久久久久国产精品嫩草影院
精品99又大又爽又硬少妇毛片 | 精品无人乱码| 国产麻豆一区二区三区精品| 欧洲一区av| 国产尤物视频在线| 狠狠干五月天| 国产一级免费在线观看| 国产精品ⅴa有声小说| 精品剧情v国产在线观看| www.91在线播放| 中文字幕免费在线视频| av黄色在线观看| 黄色网址在线免费播放| 国产一卡2卡3卡四卡网站| 国产福利微拍精品一区二区| 伊人中文在线| 国产在线资源| 在线一区观看| 丁香花在线电影小说观看 | www.色五月| 午夜视频在线看| 国产欧美日韩第一页| gogogogo高清视频在线| 国产深夜福利| 麻豆网站在线免费观看| 国产色在线 com| 免费看的毛片| 精品视频麻豆入口| 午夜视频99| 波多野结衣久久高清免费| 中文字幕av中文字幕| 日本国产在线| 国产香蕉视频在线看| 精品美女视频在线观看免费软件| 免费看成年人视频在线观看| 在线午夜视频| 国产精品视频h| 中文字幕视频在线观看| 欧美日韩亚洲第一页| 在线中文视频| 国产91在线视频蝌蚪| 国产国语**毛片高清视频| 尤物视频在线看| 国产中文字幕网| 九九热在线免费视频| 永久免费av网站| 国产精品麻豆一区二区三区| 超碰国产在线| 日本一本久久| 美女网站在线观看| 激情综合丁香| 黄色片av在线| 国产麻豆精品一区二区三区v视界| eeuss在线观看| 狠狠操狠狠色| 国产一区二区三区美女秒播| 成人超碰在线| 国产一区二区三区不卡免费观看 | 九九热视频在线| 久热精品免费视频| 欧洲一区av| 国产免费一级| 国产porn在线| 日本一卡二卡四卡精品| 国产在线观看a| 国产尤物一区二区三区| 国产精品国产国产aⅴ| 在线观看wwww| 国产精选在线观看| 国产精品18久久久久久久久久| 国产精品福利视频一区二区三区| av大片在线播放| 国产美女高潮| 精品一区二区三区免费站| 亚洲欧美精选| 国产一区二区三区福利| 亚洲视频在线网| 国产乱妇乱子| av网站大全在线观看| 国产在线看片| 色吊丝av中文字幕| 中中文字幕av在线| 三级小说一区| 国产极品视频| 天天操天天艹| 女同一区二区免费aⅴ| 国产女主播在线观看| 欧美性猛交p30| 国产网红女主播精品视频| 日韩亚洲一区中文字幕| 国产一区久久精品| 免费在线观看a| h网址在线观看| av麻豆国产| 7777在线| 国产黄视频在线观看| 国产美女一区视频| 激情丁香久久| 国产在线麻豆精品| 麻豆福利在线观看| 青青免费在线视频| 亚洲电影先锋| 在线播放一区二区精品产| 福利视频网站导航| www.狠狠艹| 黄色片视频在线观看| 久久这里精品| 国产在线观看18| 国产在线二区| 中文字幕在线观看av| 日本中文字幕视频在线| 尤物视频在线免费观看| 国产麻豆精品入口在线观看| 二区三区中文字幕| √天堂中文在线| 国产欧美一区二区三区小说| 国产va在线观看| 午夜影院在线| 超碰在线网址| 国产调教视频在线观看| 国产精品国产三级国产试看| 国产成人精品18| 992tv在线观看在线播放| 在线观看的av网站| 男人天堂99| 国产在线二区| 国产黄在线播放| 天天干天天摸| 中文字幕在线观看播放| 国产黄色片大全| 亚洲综合色视频在线观看| 亚洲综合在线不卡| 国产在线观看18| 2019天天操夜夜操| 在线观看中文字幕的网站| 玖玖在线视频| 国产激情视频在线| 久久99国产视频| 国产成人亚洲欧美电影| www在线播放| 国产95在线|亚洲| 中文字幕高清av| 麻豆国产在线播放| 精精国产xxxx视频在线中文版| 狠狠狠狠狠狠操| 日本在线免费中文字幕| 国产娇喘精品一区二区三区图片| 国产在线观看色| 依依成人在线| 五月婷婷在线视频| 超碰国产在线| 日本欧美在线视频免费观看| 中文字幕第一页av| 久久久久久久久免费视频| 99免费视频| 精品亚洲成a人片在线观看| 国产网站免费看| 五月天丁香在线| 天堂在线看视频| 国产在线一二三| 麻豆国产视频| 青青草在线视频免费观看| 亚洲一本大道| 日本视频二区| 亚洲精品天堂在线| 精品一二三区视频| 精品一区二区观看| 91蜜桃在线视频| 精品亚洲综合| 在线观看电影av| 在线视频三级| 999在线视频| 在线观看视频污| 日本在线视频www鲁啊鲁| 天天艹天天操| 久久精品免视着国产成人| 国产主播色在线| 国产午夜精品久久久久免费视| 国产精品9区| 国产精品视频福利一区二区| 国产精品9区| 亚洲成人电视网| 国产秒拍福利视频露脸| 天天操天天艹| 91在线网站| 九色成人在线| 国产精品免费视频一区一| 91这里只有精品| 青青青手机在线视频观看| 国产麻豆免费| 在线观看的av| 午夜伦全在线观看| 精品国产一区二区三区不卡在线| 中文一区在线观看| 伊人影院在线播放| 国产主播福利在线| 在线国产91| 国产特级嫩嫩嫩bbb| 在线免费看av| 天天操天天曰|