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

首頁 > 編程 > Java > 正文

淺談Java編程中的單例設計模式

2019-11-26 15:02:08
字體:
來源:轉載
供稿:網友

寫軟件的時候經常需要用到打印日志功能,可以幫助你調試和定位問題,項目上線后還可以幫助你分析數據。但是Java原生帶有的System.out.println()方法卻很少在真正的項目開發中使用,甚至像findbugs等代碼檢查工具還會認為使用System.out.println()是一個bug。

為什么作為Java新手神器的System.out.println(),到了真正項目開發當中會被唾棄呢?其實只要細細分析,你就會發現它的很多弊端。比如不可控制,所有的日志都會在項目上線后照常打印,從而降低運行效率;又或者不能將日志記錄到本地文件,一旦打印被清除,日志將再也找不回來;再或者打印的內容沒有Tag區分,你將很難辨別這一行日志是在哪個類里打印的。

你的leader也不是傻瓜,用System.out.println()的各項弊端他也清清楚楚,因此他今天給你的任務就是制作一個日志工具類,來提供更好的日志功能。不過你的leader人還不錯,并沒讓你一開始就實現一個具備各項功能的牛逼日志工具類,只需要一個能夠控制打印級別的日志工具就好。

這個需求對你來說并不難,你立刻就開始動手編寫了,并很快完成了第一個版本:

  public class LogUtil {     public final int DEBUG = 0;        public final int INFO = 1;        public final int ERROR = 2;        public final int NOTHING = 3;        public int level = DEBUG;        public void debug(String msg) {       if (DEBUG >= level) {         System.out.println(msg);       }     }        public void info(String msg) {       if (INFO >= level) {         System.out.println(msg);       }     }        public void error(String msg) {       if (ERROR >= level) {         System.out.println(msg);       }     }   } 



通過這個類來打印日志,只需要控制level的級別,就可以自由地控制打印的內容。比如現在項目處于開發階段,就將level設置為DEBUG,這樣所有的日志信息都會被打印。而項目如果上線了,可以把level設置為INFO,這樣就只能看到INFO及以上級別的日志打印。如果你只想看到錯誤日志,就可以把level設置為ERROR。而如果你開發的項目是客戶端版本,不想讓任何日志打印出來,可以將level設置為NOTHING。打印的時候只需要調用:

  new LogUtil().debug("Hello World!"); 



你迫不及待地將這個工具介紹給你的leader,你的leader聽完你的介紹后說:“好樣的,今后大伙都用你寫的這個工具來打印日志了!”

可是沒過多久,你的leader找到你來反饋問題了。他說雖然這個工具好用,可是打印這種事情是不區分對象的,這里每次需要打印日志的時候都需要new出一個新的LogUtil,太占用內存了,希望你可以將這個工具改成用單例模式實現。

你認為你的leader說的很有道理,而且你也正想趁這個機會練習使用一下設計模式,于是你寫出了如下的代碼(ps:這里代碼是我自己實現的,而且我開始確實沒注意線程同步問題):

  public class LogUtil {     private static LogUtil logUtilInstance;        public final int DEBUG = 0;        public final int INFO = 1;        public final int ERROR = 2;        public final int NOTHING = 3;        public int level = DEBUG;        private LogUtil() {        }        public static LogUtil getInstance() {       if (logUtilInstance == null) {         logUtilInstance = new LogUtil();       }          return logUtilInstance;     }        public void debug(String msg) {       if (DEBUG >= level) {         System.out.println(msg);       }     }        public void info(String msg) {       if (INFO >= level) {         System.out.println(msg);       }     }        public void error(String msg) {       if (ERROR >= level) {         System.out.println(msg);       }     }        public static void main(String[] args) {       LogUtil.getInstance().debug("Hello World!");     }   } 


首先將LogUtil的構造函數私有化,這樣就無法使用new關鍵字來創建LogUtil的實例了。然后使用一個sLogUtil私有靜態變量來保存實例,并提供一個公有的getInstance方法用于獲取LogUtil的實例,在這個方法里面判斷如果sLogUtil為空,就new出一個新的LogUtil實例,否則就直接返回sLogUtil。這樣就可以保證內存當中只會存在一個LogUtil的實例了。單例模式完工!這時打印日志的代碼需要改成如下方式:

  LogUtil.getInstance().debug("Hello World");  


你將這個版本展示給你的leader瞧,他看后笑了笑,說:“雖然這看似是實現了單例模式,可是還存在著bug的哦。
你滿腹狐疑,單例模式不都是這樣實現的嗎?還會有什么bug呢?

你的leader提示你,使用單例模式就是為了讓這個類在內存中只能有一個實例的,可是你有考慮到在多線程中打印日志的情況嗎?如下面代碼所示:

  public static LogUtil getInstance() {     if (logUtilInstance == null) {       logUtilInstance = new LogUtil();     }        return logUtilInstance;   } 


如果現在有兩個線程同時在執行getInstance方法,第一個線程剛執行完第2行,還沒執行第3行,這個時候第二個線程執行到了第2行,它會發現sLogUtil還是null,于是進入到了if判斷里面。這樣你的單例模式就失敗了,因為創建了兩個不同的實例。
你恍然大悟,不過你的思維非??欤⒖叹拖氲搅私鉀Q辦法,只需要給方法加上同步鎖就可以了,代碼如下:

  public synchronized static LogUtil getInstance() {     if (logUtilInstance == null) {       logUtilInstance = new LogUtil();     }        return logUtilInstance;   } 


這樣,同一時刻只允許有一個線程在執行getInstance里面的代碼,這樣就有效地解決了上面會創建兩個實例的情況。
你的leader看了你的新代碼后說:“恩,不錯。這確實解決了有可能創建兩個實例的情況,但是這段代碼還是有問題的?!?/p>

你緊張了起來,怎么還會有問題???

你的leader笑笑:“不用緊張,這次不是bug,只是性能上可以優化一些。你看一下,如果是在getInstance方法上加了一個synchronized,那么我每次去執行getInstace方法的時候都會受到同步鎖的影響,這樣運行的效率會降低,其實只需要在第一次創建LogUtil實例的時候加上同步鎖就好了。我來教你一下怎么把它優化的更好?!?/p>

首先將synchronized關鍵字從方法聲明中去除,把它加入到方法體當中:

  public static LogUtil getInstance() {     if (logUtilInstance == null) {       synchronized (LogUtil.class) {         if (logUtilInstance == null) {           // 這里是必須的,因為有可能兩個進程同時執行到synchronized之前           logUtilInstance = new LogUtil();         }       }     }        return logUtilInstance;   } 


代碼改成這樣之后,只有在sLogUtil還沒被初始化的時候才會進入到第3行,然后加上同步鎖。等sLogUtil一但初始化完成了,就再也走不到第3行了,這樣執行getInstance方法也不會再受到同步鎖的影響,效率上會有一定的提升。
你情不自禁贊嘆到,這方法真巧妙啊,能想得出來實在是太聰明了。

你的leader馬上謙虛起來:“這種方法叫做雙重鎖定(Double-Check Locking),可不是我想出來的,更多的資料你可以在網上查一查?!?/p>

其實在java里實現單例我更習慣用餓漢模式

懶漢式的特點是延遲加載,實例直到用到的時候才會加載

餓漢式的特點是一開始就加載了,所以每次用到的時候直接返回即可(我更推薦這一種,因為不需要考慮太多線程安全的問題,當然懶漢式是可以通過上文所說的雙重鎖定解決同步問題的)

用餓漢式實現日志記錄的代碼如下:

  public class LogUtil {     private static final LogUtil logUtilInstance = new LogUtil();        public final int DEBUG = 0;        public final int INFO = 1;        public final int ERROR = 2;        public final int NOTHING = 3;        public int level = DEBUG;        private LogUtil() {        }        public static LogUtil getInstance() {       return logUtilInstance;     }        public void debug(String msg) {       if (DEBUG >= level) {         System.out.println(msg);       }     }        public void info(String msg) {       if (INFO >= level) {         System.out.println(msg);       }     }        public void error(String msg) {       if (ERROR >= level) {         System.out.println(msg);       }     }        public static void main(String[] args) {       logUtil.getInstance().debug("Hello World!");     }   } 


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲人成在线观看| 久久精品视频网站| 亚洲精品自拍第一页| 亚洲人成绝费网站色www| 国产精品入口福利| 亚洲伦理中文字幕| 亚洲精品一区二区在线| 亚洲精品有码在线| 中日韩美女免费视频网站在线观看| 2021国产精品视频| 欧美疯狂性受xxxxx另类| 国产精品久久久久不卡| 91色在线视频| 亚洲精品mp4| 欧美亚洲另类激情另类| 日韩一二三在线视频播| 国产69久久精品成人| 亚洲色图综合网| 韩国福利视频一区| 在线一区二区日韩| 欧美最猛性xxxxx(亚洲精品)| 欧美极度另类性三渗透| 欧美高清videos高潮hd| 中文字幕av一区中文字幕天堂| 久久伊人免费视频| 国产日韩亚洲欧美| 亚洲永久免费观看| 国产日韩欧美电影在线观看| 中文字幕亚洲色图| 欧美日韩国产色| 欧美xxxx做受欧美.88| 国语自产在线不卡| 亚洲精品视频中文字幕| 久久久久久久久久久成人| 欧美日韩精品二区| 久久人人爽人人| 国产欧美一区二区三区久久| 成人综合网网址| 亚洲女同性videos| 国产狼人综合免费视频| 91青草视频久久| 成人免费网站在线观看| 97视频在线观看免费| 久青草国产97香蕉在线视频| 国产精品视频免费在线| 久久97久久97精品免视看| 日本欧美国产在线| 国产精品永久免费观看| 久久久国产一区| 国产综合福利在线| 国产精品91久久| 亚洲精品欧美一区二区三区| 久久精品在线视频| 狠狠躁夜夜躁人人爽超碰91| 久久婷婷国产麻豆91天堂| 欧美在线性爱视频| 久久久国产精彩视频美女艺术照福利| 欧美日韩国产激情| 国产成人精品999| 亚洲精品资源在线| 一区二区三区四区在线观看视频| 欧美日韩国产va另类| 国产精品专区一| 欧美一级在线亚洲天堂| 日韩在线免费高清视频| 91视频免费网站| 日韩在线激情视频| 国产成人亚洲综合91| 亚洲女同精品视频| 亚洲女人天堂视频| 国产精品成人一区| 欧美日韩精品中文字幕| 久久成人这里只有精品| 久青草国产97香蕉在线视频| 日韩激情av在线免费观看| 在线精品91av| 欧美大成色www永久网站婷| 国产成人啪精品视频免费网| 欧美午夜精品久久久久久久| 久久久久成人网| 亚洲欧美成人一区二区在线电影| 精品无码久久久久久国产| 日韩精品中文在线观看| 岛国av一区二区三区| 亚洲国产中文字幕久久网| 亚洲日本中文字幕| 国产日本欧美一区二区三区在线| 国产成人精品久久亚洲高清不卡| 国产偷亚洲偷欧美偷精品| 欧美精品在线免费| 久久久久久18| 亚洲成人精品久久久| 92福利视频午夜1000合集在线观看| 97免费视频在线播放| 97婷婷大伊香蕉精品视频| 亚洲成人av资源网| 日韩av资源在线播放| 91成品人片a无限观看| 日韩精品免费在线视频观看| 97在线免费视频| 91精品国产高清自在线| 色婷婷久久一区二区| 亚洲新中文字幕| 国产欧亚日韩视频| 亚州av一区二区| 久久影视电视剧凤归四时歌| 欧美日韩免费网站| 欧美专区日韩视频| 久久午夜a级毛片| 国产欧美精品日韩| 一本色道久久88综合亚洲精品ⅰ| 欧美在线亚洲在线| 成人黄色午夜影院| 亚洲精品欧美一区二区三区| 欧美日韩免费在线观看| 久久91精品国产| 免费97视频在线精品国自产拍| 久久亚洲欧美日韩精品专区| 成人免费视频在线观看超级碰| 亚洲国产精品嫩草影院久久| 91视频8mav| 深夜福利一区二区| 黑人巨大精品欧美一区二区三区| 亚洲影视中文字幕| 亚洲bt天天射| 亚洲精品黄网在线观看| 成人伊人精品色xxxx视频| 国产成人精品视| 97婷婷大伊香蕉精品视频| 色老头一区二区三区| 国产午夜精品视频免费不卡69堂| 久久久久久久久久国产精品| 亚洲欧洲一区二区三区久久| 亚洲最新av在线网站| 日韩综合视频在线观看| 国产亚洲成av人片在线观看桃| 成人天堂噜噜噜| 国产z一区二区三区| 欧美野外猛男的大粗鳮| 亚洲自拍偷拍色片视频| 黄色成人av在线| 国产成人精品在线视频| 欧美日韩高清区| 91老司机在线| 最好看的2019年中文视频| 51ⅴ精品国产91久久久久久| 精品福利樱桃av导航| 亚洲人成网7777777国产| 国产精品免费久久久| 永久免费毛片在线播放不卡| 成人精品一区二区三区电影免费| xxav国产精品美女主播| 亚洲国产成人久久综合| 久久夜色精品国产| 亚洲视频免费一区| 国产精品一区二区三区久久久| 黑人巨大精品欧美一区免费视频| 日本久久久a级免费| 日韩网站免费观看高清| 久久精品青青大伊人av| 日本成人黄色片| 久久国产精品久久久久久久久久| 亚洲理论片在线观看| 爱福利视频一区|