亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Java > 正文

Java開發的23種涉及模式

2019-11-11 06:04:05
字體:
來源:轉載
供稿:網友
在GoF的23種設計模式中,單例模式是比較簡單的一種。然而,有時候越是簡單的東西越容易出現問題。下面就單例設計模式詳細的探討一下。 所謂單例模式,簡單來說,就是在整個應用中保證只有一個類的實例存在。就像是java Web中的application,也就是提供了一個全局變量,用處相當廣泛,比如保存全局數據,實現全局性的操作等。 1. 最簡單的實現 首先,能夠想到的最簡單的實現是,把類的構造函數寫成PRivate的,從而保證別的類不能實例化此類,然后在類中提供一個靜態的實例并能夠返回給使用者。這樣,使用者就可以通過這個引用使用到這個類的實例了。 public class SingletonClass {   private static final SingletonClass instance = new SingletonClass();       public static SingletonClass getInstance() {     return instance;   }       private SingletonClass() {        }     } 如上例,外部使用者如果需要使用SingletonClass的實例,只能通過getInstance()方法,并且它的構造方法是private的,這樣就保證了只能有一個對象存在。 2. 性能優化——lazy loaded 上面的代碼雖然簡單,但是有一個問題——無論這個類是否被使用,都會創建一個instance對象。如果這個創建過程很耗時,比如需要連接10000次數據庫(夸張了…:-)),并且這個類還并不一定會被使用,那么這個創建過程就是無用的。怎么辦呢? 為了解決這個問題,我們想到了新的解決方案: public class SingletonClass {   private static SingletonClass instance = null;       public static SingletonClass getInstance() {     if(instance == null) {       instance = new SingletonClass();     }     return instance;   }       private SingletonClass() {        }     } 代碼的變化有兩處——首先,把instance初始化為null,直到第一次使用的時候通過判斷是否為null來創建對象。因為創建過程不在聲明處,所以那個final的修飾必須去掉。 我們來想象一下這個過程。要使用SingletonClass,調用getInstance()方法。第一次的時候發現instance是null,然后就新建一個對象,返回出去;第二次再使用的時候,因為這個instance是static的,所以已經不是null了,因此不會再創建對象,直接將其返回。 這個過程就成為lazy loaded,也就是遲加載——直到使用的時候才進行加載。 3. 同步 上面的代碼很清楚,也很簡單。然而就像那句名言:“80%的錯誤都是由20%代碼優化引起的”。單線程下,這段代碼沒有什么問題,可是如果是多線程,麻煩就來了。我們來分析一下: 線程A希望使用SingletonClass,調用getInstance()方法。因為是第一次調用,A就發現instance是null的,于是它開始創建實例,就在這個時候,CPU發生時間片切換,線程B開始執行,它要使用SingletonClass,調用getInstance()方法,同樣檢測到instance是null——注意,這是在A檢測完之后切換的,也就是說A并沒有來得及創建對象——因此B開始創建。B創建完成后,切換到A繼續執行,因為它已經檢測完了,所以A不會再檢測一遍,它會直接創建對象。這樣,線程A和B各自擁有一個SingletonClass的對象——單例失??! 解決的方法也很簡單,那就是加鎖: public class SingletonClass {   private static SingletonClass instance = null;       public synchronized static SingletonClass getInstance() {     if(instance == null) {       instance = new SingletonClass();     }     return instance;   }       private SingletonClass() {        }     } 是要getInstance()加上同步鎖,一個線程必須等待另外一個線程創建完成后才能使用這個方法,這就保證了單例的唯一性。 4. 又是性能 上面的代碼又是很清楚很簡單的,然而,簡單的東西往往不夠理想。這段代碼毫無疑問存在性能的問題——synchronized修飾的同步塊可是要比一般的代碼段慢上幾倍的!如果存在很多次getInstance()的調用,那性能問題就不得不考慮了! 讓我們來分析一下,究竟是整個方法都必須加鎖,還是僅僅其中某一句加鎖就足夠了?我們為什么要加鎖呢?分析一下出現lazy loaded的那種情形的原因。原因就是檢測null的操作和創建對象的操作分離了。如果這兩個操作能夠原子地進行,那么單例就已經保證了。于是,我們開始修改代碼: public class SingletonClass {   private static SingletonClass instance = null;       public static SingletonClass getInstance() {     synchronized (SingletonClass.class) {       if(instance == null) {         instance = new SingletonClass();       }     }         return instance;   }       private SingletonClass() {        }     } 首先去掉getInstance()的同步操作,然后把同步鎖加載if語句上。但是這樣的修改起不到任何作用:因為每次調用getInstance()的時候必然要同步,性能問題還是存在。如果……如果我們事先判斷一下是不是為null再去同步呢? public class SingletonClass {   private static SingletonClass instance = null;   public static SingletonClass getInstance() {     if (instance == null) {       synchronized (SingletonClass.class) {         if (instance == null) {           instance = new SingletonClass();         }       }     }     return instance;   }   private SingletonClass() {   } } 還有問題嗎?首先判斷instance是不是為null,如果為null,加鎖初始化;如果不為null,直接返回instance。 這就是double-checked locking設計實現單例模式。到此為止,一切都很完美。我們用一種很聰明的方式實現了單例模式。 5. 從源頭檢查 下面我們開始說編譯原理。所謂編譯,就是把源代碼“翻譯”成目標代碼——大多數是指機器代碼——的過程。針對Java,它的目標代碼不是本地機器代碼,而是虛擬機代碼。編譯原理里面有一個很重要的內容是編譯器優化。所謂編譯器優化是指,在不改變原來語義的情況下,通過調整語句順序,來讓程序運行的更快。這個過程成為reorder。 要知道,JVM只是一個標準,并不是實現。JVM中并沒有規定有關編譯器優化的內容,也就是說,JVM實現可以自由的進行編譯器優化。 下面來想一下,創建一個變量需要哪些步驟呢?一個是申請一塊內存,調用構造方法進行初始化操作,另一個是分配一個指針指向這塊內存。這兩個操作誰在前誰在后呢?JVM規范并沒有規定。那么就存在這么一種情況,JVM是先開辟出一塊內存,然后把指針指向這塊內存,最后調用構造方法進行初始化。 下面我們來考慮這么一種情況:線程A開始創建SingletonClass的實例,此時線程B調用了getInstance()方法,首先判斷instance是否為null。按照我們上面所說的內存模型,A已經把instance指向了那塊內存,只是還沒有調用構造方法,因此B檢測到instance不為null,于是直接把instance返回了——問題出現了,盡管instance不為null,但它并沒有構造完成,就像一套房子已經給了你鑰匙,但你并不能住進去,因為里面還沒有收拾。此時,如果B在A將instance構造完成之前就是用了這個實例,程序就會出現錯誤了! 于是,我們想到了下面的代碼: public class SingletonClass {   private static SingletonClass instance = null;   public static SingletonClass getInstance() {     if (instance == null) {       SingletonClass sc;       synchronized (SingletonClass.class) {         sc = instance;         if (sc == null) {           synchronized (SingletonClass.class) {             if(sc == null) {               sc = new SingletonClass();             }           }           instance = sc;         }       }     }     return instance;   }   private SingletonClass() {   }     } 我們在第一個同步塊里面創建一個臨時變量,然后使用這個臨時變量進行對象的創建,并且在最后把instance指針臨時變量的內存空間。寫出這種代碼基于以下思想,即synchronized會起到一個代碼屏蔽的作用,同步塊里面的代碼和外部的代碼沒有聯系。因此,在外部的同步塊里面對臨時變量sc進行操作并不影響instance,所以外部類在instance=sc;之前檢測instance的時候,結果instance依然是null。 不過,這種想法完全是錯誤的!同步塊的釋放保證在此之前——也就是同步塊里面——的操作必須完成,但是并不保證同步塊之后的操作不能因編譯器優化而調換到同步塊結束之前進行。因此,編譯器完全可以把instance=sc;這句移到內部同步塊里面執行。這樣,程序又是錯誤的了! 6. 解決方案 說了這么多,難道單例沒有辦法在Java中實現嗎?其實不然! 在JDK 5之后,Java使用了新的內存模型。volatile關鍵字有了明確的語義——在JDK1.5之前,volatile是個關鍵字,但是并沒有明確的規定其用途——被volatile修飾的寫變量不能和之前的讀寫代碼調整,讀變量不能和之后的讀寫代碼調整!因此,只要我們簡單的把instance加上volatile關鍵字就可以了。 public class SingletonClass {   private volatile static SingletonClass instance = null;   public static SingletonClass getInstance() {     if (instance == null) {       synchronized (SingletonClass.class) {         if(instance == null) {           instance = new SingletonClass();         }       }     }     return instance;   }   private SingletonClass() {   }     } 然而,這只是JDK1.5之后的Java的解決方案,那之前版本呢?其實,還有另外的一種解決方案,并不會受到Java版本的影響: public class SingletonClass {       private static class SingletonClassInstance {     private static final SingletonClass instance = new SingletonClass();   }   public static SingletonClass getInstance() {     return SingletonClassInstance.instance;   }   private SingletonClass() {   }     } 在這一版本的單例模式實現代碼中,我們使用了Java的靜態內部類。這一技術是被JVM明確說明了的,因此不存在任何二義性。在這段代碼中,因為SingletonClass沒有static的屬性,因此并不會被初始化。直到調用getInstance()的時候,會首先加載SingletonClassInstance類,這個類有一個static的SingletonClass實例,因此需要調用SingletonClass的構造方法,然后getInstance()將把這個內部類的instance返回給使用者。由于這個instance是static的,因此并不會構造多次。 由于SingletonClassInstance是私有靜態內部類,所以不會被其他類知道,同樣,static語義也要求不會有多個實例存在。并且,JSL規范定義,類的構造必須是原子性的,非并發的,因此不需要加同步塊。同樣,由于這個構造是并發的,所以getInstance()也并不需要加同步。 至此,我們完整的了解了單例模式在Java語言中的時候,提出了兩種解決方案。個人偏向于第二種,并且Effiective Java也推薦的這種方式。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩视频免费观看| 伊人伊成久久人综合网小说| 一区二区三区久久精品| 国产午夜一区二区| 日韩av电影在线网| 亚洲欧洲在线播放| 日韩av在线不卡| 日韩中文字幕国产| 91理论片午午论夜理片久久| 国产欧美一区二区白浆黑人| 国内免费久久久久久久久久久| 国产精品久久97| 亚洲第一网站男人都懂| 午夜精品久久久久久99热软件| 国产亚洲精品久久久久久777| 国产精品久久久久7777婷婷| 亚洲精品网址在线观看| 日本亚洲欧美三级| 中文字幕欧美精品在线| 国产成人一区二区| 日韩精品视频观看| 久久综合免费视频影院| 国产精品人成电影| 亲爱的老师9免费观看全集电视剧| 欧美性xxxx极品高清hd直播| 国产精品人成电影在线观看| 成人有码在线播放| 国产最新精品视频| 中文字幕精品在线视频| 中文字幕九色91在线| 国产精品在线看| 成人黄色av免费在线观看| 国产性猛交xxxx免费看久久| 亚洲男人7777| 亚洲欧美日韩第一区| 美女999久久久精品视频| 欧美精品福利视频| 亚洲国产精品悠悠久久琪琪| 午夜精品久久久久久久久久久久| 日韩在线免费高清视频| 26uuu久久噜噜噜噜| 欧美日韩亚洲高清| 国产精品扒开腿做爽爽爽视频| 亚洲成人av中文字幕| 亚洲人成电影网站色www| 国产精品久久久久久久9999| 亚洲第一精品福利| 亚洲美女免费精品视频在线观看| 欧美色播在线播放| 日韩精品一区二区三区第95| 亚洲视频在线免费观看| 久久久久久12| 中文在线不卡视频| 欧美激情综合色综合啪啪五月| 国产精品成人一区二区| 国产日韩欧美夫妻视频在线观看| 亚洲一区二区久久久久久久| 国产精品成人一区| 超在线视频97| 欧美成人午夜影院| 午夜精品视频在线| 国模极品一区二区三区| 久久激情五月丁香伊人| 91性高湖久久久久久久久_久久99| 日韩少妇与小伙激情| 日韩高清电影免费观看完整| 97碰在线观看| 欧美日韩综合视频| 国产精品一区二区久久久久| 高清亚洲成在人网站天堂| 亚洲欧美日韩精品久久| 国内精品久久久久影院优| 久久久久久久网站| 久久久亚洲天堂| 亚洲美女av在线播放| 久久91精品国产91久久久| 久久久999精品视频| 91欧美激情另类亚洲| 啪一啪鲁一鲁2019在线视频| 久久久精品日本| 免费不卡在线观看av| 中文字幕免费精品一区高清| 日韩av一区在线观看| 国产丝袜一区二区| 久久久精品电影| 精品福利樱桃av导航| 日韩av综合网站| 国产色婷婷国产综合在线理论片a| 国产精品偷伦视频免费观看国产| 亚洲片国产一区一级在线观看| 97不卡在线视频| 亚洲国产成人在线视频| 日韩视频欧美视频| 91成人在线观看国产| 成人做爽爽免费视频| 国产成人精品在线| 亚洲91av视频| 中文字幕日韩av| 欧美老少做受xxxx高潮| 国产丝袜一区视频在线观看| 原创国产精品91| 亚洲日本中文字幕免费在线不卡| 色琪琪综合男人的天堂aⅴ视频| 日韩国产高清污视频在线观看| 亚洲综合色av| 欧美日韩国产一中文字不卡| 欧美福利视频在线观看| 国模gogo一区二区大胆私拍| 久热精品视频在线观看| 美女999久久久精品视频| 不卡中文字幕av| 精品福利在线看| y97精品国产97久久久久久| 91精品久久久久久久久中文字幕| 欧美性猛交丰臀xxxxx网站| 日韩欧美a级成人黄色| 日韩精品免费在线视频| 日韩hd视频在线观看| 欧美精品一区二区免费| 久久久国产在线视频| 色香阁99久久精品久久久| 欧美激情视频网址| 精品国产欧美一区二区三区成人| 国产成人亚洲精品| 69国产精品成人在线播放| 欧美日韩国产一区二区三区| 久久久久久69| 国产成人短视频| 精品国产1区2区| 日韩国产在线播放| 97视频在线免费观看| 91av中文字幕| 亚洲男人的天堂在线| 国产香蕉97碰碰久久人人| 亚洲精品美女视频| 国产精品露脸av在线| 亚洲免费视频一区二区| 日韩精品视频在线观看免费| 欧美另类极品videosbest最新版本| 亚洲欧洲av一区二区| 最近更新的2019中文字幕| 国产精品露脸自拍| xxx成人少妇69| 在线播放国产一区中文字幕剧情欧美| 成人免费网视频| 亚洲风情亚aⅴ在线发布| 欧美激情伊人电影| 欧美精品成人91久久久久久久| 国产精品av在线| 亚洲精品小视频| 欧美日韩视频免费播放| 欧美激情a∨在线视频播放| 在线午夜精品自拍| 亚洲欧洲日韩国产| 少妇激情综合网| 亚洲精品日韩欧美| 久久婷婷国产麻豆91天堂| 欧美在线视频一区二区| 久久久久久噜噜噜久久久精品| 日韩在线中文字幕| 国产精品久久久久7777婷婷| 国产成人aa精品一区在线播放| 国内偷自视频区视频综合| 国产精品久久久久7777婷婷|