首先寫個(gè)單例:
public class SingleDemo { private static SingleDemo s = null; private SingleDemo(){} public static SingleDemo getInstance(){ if(s == null){ s = new SingleDemo(); } return s; } } 寫個(gè)測試類:
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,說明單線程下是沒問題的,下面寫個(gè)多線程來訪問單例
public class ThreadTest implements Runnable { //存放單例對象,使用Set是為了不存放重復(fù)元素 public Set<SingleDemo> singles = new HashSet<SingleDemo>(); @Override public void run() { //獲取單例 SingleDemo s = SingleDemo.getInstance(); //添加單例 singles.add(s); } } 使用多線程并發(fā)訪問單例:
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]
說明有線程并發(fā)訪問安全問題,獲取的不一定都是同一個(gè)實(shí)例
如何解決線程安全問題呢?
當(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ù)后線程安全問題解決了
運(yùn)行多次都是獲取同一個(gè)實(shí)例,不會出現(xiàn)2個(gè)實(shí)例的情況了
[com.persagy.thread.SingleDemo@12b6651]
但是在多線程并發(fā)訪問的情況下,每個(gè)線程每次獲取實(shí)例都要判斷下鎖,效率比較低,為了提高效率,我加入了雙重判斷的方法,解決了效率的問題
代碼如下:
public class SingleDemo { private static SingleDemo s = null; private SingleDemo(){} public static SingleDemo getInstance(){ /*如果第一個(gè)線程獲取到了單例的實(shí)例對象, * 后面的線程再獲取實(shí)例的時(shí)候不需要進(jìn)入同步代碼塊中了*/ if(s == null){ //同步代碼塊用的鎖是單例的字節(jié)碼文件對象,且只能用這個(gè)鎖 synchronized(SingleDemo.class){ if(s == null){ s = new SingleDemo(); } } } return s; }}用這種方式解決了懶漢式的線程安全問題,也提高了效率,但是在實(shí)際開發(fā)中還是用餓漢式的比較多,畢竟這個(gè)代碼比較多,比較繁瑣。
以上就是小編為大家?guī)淼耐昝澜鉀Q單例設(shè)計(jì)模式中懶漢式線程安全的問題全部內(nèi)容了,希望大家多多支持武林網(wǎng)~
新聞熱點(diǎn)
疑難解答
圖片精選