餓漢式單例執行緒安全問題以及提高效率
阿新 • • 發佈:2019-01-06
首先寫個單例:
public class SingleDemo {
private static SingleDemo s = null;
private SingleDemo(){}
public static SingleDemo getInstance(){
if(s == null){
s = new SingleDemo();
}
return s;
}
}
寫個測試類:
public class ThreadDemo3 {
public static void main(String[] args) {
SingleDemo s1 = SingleDemo.getInstance();
SingleDemo s2 = SingleDemo.getInstance();
System.out.println(s2 == s2);
}
}
執行結果一直都是true,說明單執行緒下是沒問題的,下面寫個多執行緒來訪問單例
public class ThreadTest implements Runnable {
//存放單例物件,使用Set是為了不存放重複元素
public Set<SingleDemo> singles = new HashSet<SingleDemo>();
@Override
public void run() {
//獲取單例
SingleDemo s = SingleDemo.getInstance();
//新增單例
singles.add(s);
}
}
使用多執行緒併發訪問單例:
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);
}
}
執行結果如下:
[[email protected], [email protected]]
或
說明有執行緒併發訪問安全問題,獲取的不一定都是同一個例項
如何解決執行緒安全問題呢?
當然使用同步鎖機制了啊
下面改進單例:
public class SingleDemo {
private static SingleDemo s = null;
private SingleDemo(){}
public static synchronized SingleDemo getInstance(){
if(s == null){
s = new SingleDemo();
}
return s;
}
}
加入同步函式後執行緒安全問題解決了
執行多次都是獲取同一個例項,不會出現2個例項的情況了
但是在多執行緒併發訪問的情況下,每個執行緒每次獲取例項都要判斷下鎖,效率比較低,為了提高效率,我加入了雙重判斷的方法,解決了效率的問題
程式碼如下;
public class SingleDemo {
private static SingleDemo s = null;
private SingleDemo(){}
public static SingleDemo getInstance(){
/*如果第一個執行緒獲取到了單例的例項物件,
* 後面的執行緒再獲取例項的時候不需要進入同步程式碼塊中了*/
if(s == null){
//同步程式碼塊用的鎖是單例的位元組碼檔案物件,且只能用這個鎖
synchronized(SingleDemo.class){
if(s == null){
s = new SingleDemo();
}
}
}
return s;
}
}
用這種方式解決了懶漢式的執行緒安全問題,也提高了效率,但是在實際開發中還是用餓漢式的比較多,畢竟這個程式碼比較多,比較繁瑣。