1. 程式人生 > >餓漢式單例執行緒安全問題以及提高效率

餓漢式單例執行緒安全問題以及提高效率

首先寫個單例:

    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]]

[[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個例項的情況了

[[email protected]]

但是在多執行緒併發訪問的情況下,每個執行緒每次獲取例項都要判斷下鎖,效率比較低,為了提高效率,我加入了雙重判斷的方法,解決了效率的問題

程式碼如下;

    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;  
        }  
    }  

用這種方式解決了懶漢式的執行緒安全問題,也提高了效率,但是在實際開發中還是用餓漢式的比較多,畢竟這個程式碼比較多,比較繁瑣。