java高級---->Thread之單例模式的使用


  這里我們介紹一下在多線程中如何安全正確的編寫單例模式的代碼。不知為何,恰如其分的話總是姍姍來遲,錯過最恰當的時機。

 

多線程中的單例模式

  這里面通過代碼來體會一下在多線程中如何正確的編寫單例模式的代碼。相同的代碼如下,不同的是Object這個類。

package com.linux.huhx.thread3.singleDesign_1;

/**
 * @Author: huhx
 * @Date: 2017-10-31 下午 4:28
 */
public class SingleDesignTest1 {
    public static void main(String[] args) {
        MyThread[] threads = new MyThread[10];
        for (int i = 0; i < 10; i++) {
            threads[i] = new MyThread();
        }
        for (int i = 0; i < 10; i++) {
            threads[i].start();
        }
    }

    static class MyThread extends Thread {
        @Override
        public void run() {
            System.out.println(MyObject*.getInstance().hashCode());
        }
    }
}

以下的不同測試類的結果,都是基於修改MyThread里面run方法的MyObject*的值。

一、立即加載方式(餓漢模式)

public class MyObject1 {
    private static MyObject1 myObject = new MyObject1();
    private MyObject1() {}

    public static MyObject1 getInstance() {
        return myObject;
    }
}

安全:一次的打印結果如下

1508118770
1508118770
1508118770
1508118770
1508118770
1508118770
1508118770
1508118770
1508118770
1508118770

 

二、延遲加載方式(懶漢模式)

public class MyObject2 {
    private static MyObject2 myObject;
    private MyObject2() {}

    public static MyObject2 getInstance() {
        try {
            if (myObject == null) {
                // 模擬一些准備的耗時操作
                TimeUnit.SECONDS.sleep(2);
                myObject = new MyObject2();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return myObject;
    }
}

不正確:一次的打印結果

401241377
355159803
1875573029
797782832
1696014491
1060834655
961745937
1060834655
1312341120
985396398

 

三、延遲加載解決方案之聲明synchronized

public class MyObject3 {
    private static MyObject3 myObject;
    private MyObject3() {}

    public synchronized static MyObject3 getInstance() {
        try {
            if (myObject == null) {
                // 模擬一些准備的耗時操作
                TimeUnit.SECONDS.sleep(2);
                myObject = new MyObject3();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return myObject;
    }
}

安全:一次的打印結果

774263507
774263507
774263507
774263507
774263507
774263507
774263507
774263507
774263507
774263507

效率比較低下:同步運行,下一個線程想要取得對象,則必須等待上一個線程釋放鎖之后,才可以繼續執行。

 

 四、延遲加載解決方案之同步代碼塊

public class MyObject4 {
    private static MyObject4 myObject;
    private MyObject4() {}

    public static MyObject4 getInstance() {
        try {
            synchronized (MyObject4.class) {
                if (myObject == null) {
                    // 模擬一些准備的耗時操作
                    TimeUnit.SECONDS.sleep(2);
                    myObject = new MyObject4();
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return myObject;
    }
}

 安全:一次的打印結果如下

1373650392
1373650392
1373650392
1373650392
1373650392
1373650392
1373650392
1373650392
1373650392
1373650392

 效率比較低下:和上述的synchronized同步方法一樣都是同步運行的。

 

五、延遲加載解決方案之同步部分代碼塊

public class MyObject5 {
    private static MyObject5 myObject;
    private MyObject5() {}

    public static MyObject5 getInstance() {
        try {
            if (myObject == null) {
                // 模擬一些准備的耗時操作
                TimeUnit.SECONDS.sleep(2);
                synchronized (MyObject5.class) {
                    myObject = new MyObject5();
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return myObject;
    }
}

不安全:一次的打印結果如下

401241377
1696014491
797782832
1875573029
1060834655
43626537
1971360294
1312341120
961745937
860826410

 

六、延遲加載解決方案之DCL雙檢查鎖機制

public class MyObject6 {
    private volatile static MyObject6 myObject;
    private MyObject6() {}

    public static MyObject6 getInstance() {
        try {
            if (myObject == null) {
                // 模擬一些准備的耗時操作
                TimeUnit.SECONDS.sleep(2);
                synchronized (MyObject6.class) {
                    if (myObject == null) {
                        myObject = new MyObject6();
                    }
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return myObject;
    }
}

安全:一次的打印結果如下

1312341120
1312341120
1312341120
1312341120
1312341120
1312341120
1312341120
1312341120
1312341120
1312341120

使用雙重檢查鎖功能,成功地解決了“懶漢模式”遇到多線程的問題。DCL也是大多數多線程結合單例模式使用的解決方案。

 

七、使用靜態內置類實現單例模式

public class MyObject7 {
    private static class MyObjectHandler {
        private static MyObject7 myObject = new MyObject7();
    }

    private MyObject7() {}

    public static MyObject7 getInstance() {
        return MyObjectHandler.myObject;
    }
}

安全:一次的打印結果如下

1240673261
1240673261
1240673261
1240673261
1240673261
1240673261
1240673261
1240673261
1240673261
1240673261

 

八、使用static代碼塊實現單例模式

public class MyObject8 {
    private static MyObject8 myObject = null;

    static {
        myObject = new MyObject8();
    }

    private MyObject8() {}

    public static MyObject8 getInstance() {
        return myObject;
    }
}

安全:一次的打印結果如下

1875573029
1875573029
1875573029
1875573029
1875573029
1875573029
1875573029
1875573029
1875573029
1875573029

 

友情鏈接

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM