完美解決單例設(shè)計(jì)模式中懶漢式線程安全的問(wèn)題
首先寫(xiě)個(gè)單例:
public class SingleDemo { private static SingleDemo s = null; private SingleDemo(){} public static SingleDemo getInstance(){ if(s == null){ s = new SingleDemo(); } return s; } }
寫(xiě)個(gè)測(cè)試類:
public class ThreadDemo3 { public static void main(String[] args) { SingleDemo s1 = SingleDemo.getInstance(); SingleDemo s2 = SingleDemo.getInstance(); System.out.println(s2 == s2); } }
運(yùn)行結(jié)果一直都是true,說(shuō)明單線程下是沒(méi)問(wèn)題的,下面寫(xiě)個(gè)多線程來(lái)訪問(wèn)單例
public class ThreadTest implements Runnable { //存放單例對(duì)象,使用Set是為了不存放重復(fù)元素 public Set<SingleDemo> singles = new HashSet<SingleDemo>(); @Override public void run() { //獲取單例 SingleDemo s = SingleDemo.getInstance(); //添加單例 singles.add(s); } }
使用多線程并發(fā)訪問(wèn)單例:
public class ThreadDemo3 { public static void main(String[] args) { // SingleDemo s1 = SingleDemo.getInstance(); // SingleDemo s2 = SingleDemo.getInstance(); // System.out.println(s2 == s2); ThreadTest t = new ThreadTest(); new Thread(t).start(); new Thread(t).start(); new Thread(t).start(); new Thread(t).start(); new Thread(t).start(); new Thread(t).start(); new Thread(t).start(); new Thread(t).start(); System.out.println(t.singles); } }
運(yùn)行結(jié)果如下:
[com.persagy.thread.SingleDemo@1bc4459, com.persagy.thread.SingleDemo@150bd4d]
或
[com.persagy.thread.SingleDemo@12b6651]
說(shuō)明有線程并發(fā)訪問(wèn)安全問(wèn)題,獲取的不一定都是同一個(gè)實(shí)例
如何解決線程安全問(wèn)題呢?
當(dāng)然使用同步鎖機(jī)制了啊
下面改進(jìn)單例:
public class SingleDemo { private static SingleDemo s = null; private SingleDemo(){} public static synchronized SingleDemo getInstance(){ if(s == null){ s = new SingleDemo(); } return s; } }
加入同步函數(shù)后線程安全問(wèn)題解決了
運(yùn)行多次都是獲取同一個(gè)實(shí)例,不會(huì)出現(xiàn)2個(gè)實(shí)例的情況了
[com.persagy.thread.SingleDemo@12b6651]
但是在多線程并發(fā)訪問(wèn)的情況下,每個(gè)線程每次獲取實(shí)例都要判斷下鎖,效率比較低,為了提高效率,我加入了雙重判斷的方法,解決了效率的問(wèn)題
代碼如下:
public class SingleDemo { private static SingleDemo s = null; private SingleDemo(){} public static SingleDemo getInstance(){ /*如果第一個(gè)線程獲取到了單例的實(shí)例對(duì)象, * 后面的線程再獲取實(shí)例的時(shí)候不需要進(jìn)入同步代碼塊中了*/ if(s == null){ //同步代碼塊用的鎖是單例的字節(jié)碼文件對(duì)象,且只能用這個(gè)鎖 synchronized(SingleDemo.class){ if(s == null){ s = new SingleDemo(); } } } return s; } }
用這種方式解決了懶漢式的線程安全問(wèn)題,也提高了效率,但是在實(shí)際開(kāi)發(fā)中還是用餓漢式的比較多,畢竟這個(gè)代碼比較多,比較繁瑣。
以上就是小編為大家?guī)?lái)的完美解決單例設(shè)計(jì)模式中懶漢式線程安全的問(wèn)題全部?jī)?nèi)容了,希望大家多多支持腳本之家~
相關(guān)文章
Spring Boot利用Thymeleaf發(fā)送Email的方法教程
spring Boot默認(rèn)就是使用thymeleaf模板引擎的,下面這篇文章主要給大家介紹了關(guān)于在Spring Boot中利用Thymeleaf發(fā)送Email的方法教程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧。2017-08-08JUnit5中的參數(shù)化測(cè)試實(shí)現(xiàn)
參數(shù)化測(cè)試使得我們可以使用不同的參數(shù)運(yùn)行同一個(gè)測(cè)試方法,從而減少我們編寫(xiě)測(cè)試用例的工作量,本文主要介紹了JUnit5中的參數(shù)化測(cè)試實(shí)現(xiàn),感興趣的可以了解一下2023-05-05深入Spring Boot實(shí)現(xiàn)對(duì)Fat Jar jsp的支持
這篇文章主要介紹了深入Spring Boot實(shí)現(xiàn)對(duì)Fat Jar jsp的支持,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-06-06Java 客戶端操作 FastDFS 實(shí)現(xiàn)文件上傳下載替換刪除功能
這篇文章主要介紹了Java 客戶端操作 FastDFS 實(shí)現(xiàn)文件上傳下載替換刪除功能,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10java面向?qū)ο蟮娜筇匦灾焕^承用法實(shí)例分析
這篇文章主要介紹了java面向?qū)ο蟮娜筇匦灾焕^承用法,結(jié)合實(shí)例形式分析了java面向?qū)ο蟪绦蛟O(shè)計(jì)中繼承的基本原理與具體使用方法,需要的朋友可以參考下2019-11-11Springboot整合Mybatis傳值的常用方式總結(jié)
今天給大家?guī)?lái)的是關(guān)于Springboot的相關(guān)知識(shí),文章圍繞著Springboot整合Mybatis傳值的常用方式展開(kāi),文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下2021-06-06