Java多線程學習(四)

  1. 單例模式java

    1.1當即加載/餓漢模式安全

    當即加載既爲使用類的方法的時候已經將對象建立完畢。常見的實現方法就是直接new實例化。多線程

    public class MyObject {
       private static MyObject myObject = new MyObject();
      private MyObject(){}
      public static MyObject getInstance(){
         return myObject;
      }
    }
    public class MyThread extends Thread {
        public void run(){
           System.out.println(MyObject.getInstance().hashCode());
       }
       
        public static void main(String [] args){
          MyThread t1 = new MyThread();
         MyThread t2 = new MyThread();
           MyThread t3 = new MyThread();
           
           t1.start();
           t2.start();
           t3.start();
       }
    }
    運行結果爲三個線程輸出的值相同。

    1.2延遲加載/懶漢模式線程

    延遲加載既爲調用類的方法時,對象實例才被建立。常見實現方法爲在get方法中進行new實例化。code

    public class MyObject {
       private static MyObject myObject;
       private MyObject(){}
       public static MyObject getInstance(){
          if(myObject == null){ myObject = new MyObject();}
          return myObject;
       }
    }
    public class MyThread extends Thread {
        public void run(){
           System.out.println(MyObject.getInstance().hashCode());
       }
       
        public static void main(String [] args){
          MyThread t1 = new MyThread();
         MyThread t2 = new MyThread();
           MyThread t3 = new MyThread();
           
           t1.start();
           t2.start();
           t3.start();
       }
    }
    運行結果爲三個線程輸出的值不一樣,取出了多個線程實例,與單例模式相違背。

     

  2. 延遲加載的解決方案對象

    如上例所示的延遲加載方法,在多線程模式下是線程不安全的,那麼就是如下幾種解決方案吧!get

    ①聲明synchronized關鍵字同步

    既然出現線程不安全問題是由於多個線程同時進入getInstance方法致使的,那麼就給這個方法上鎖,同一時間內只有一個線程可以訪問。hash

    public class MyObject {
       private static MyObject myObject;
       private MyObject(){}
       synchronized public static MyObject getInstance(){
          if(myObject == null){ 
               myObject = new MyObject();
          }
          return myObject;
       }
    }
    public class MyThread extends Thread {
        public void run(){
           System.out.println(MyObject.getInstance().hashCode());
       }
       
        public static void main(String [] args){
          MyThread t1 = new MyThread();
         MyThread t2 = new MyThread();
           MyThread t3 = new MyThread();
           
           t1.start();
           t2.start();
           t3.start();
       }
    }
    運行結果爲三個線程輸出的值相同。

    可是這種方法的運行效率很是低下。class

    ②嘗試同步代碼塊

    public class MyObject {
       private static MyObject myObject;
       private MyObject(){}
       public static MyObject getInstance(){
             synchronized (MyObject.class){
                 if(myObject == null){ myObject = new MyObject();}
             }
             return myObject;
       }
    }
    public class MyThread extends Thread {
        public void run(){
           System.out.println(MyObject.getInstance().hashCode());
       }
       
        public static void main(String [] args){
          MyThread t1 = new MyThread();
         MyThread t2 = new MyThread();
           MyThread t3 = new MyThread();
           
           t1.start();
           t2.start();
           t3.start();
       }
    }
    運行結果爲三個線程輸出的值相同。

    可是這至關於第一種給方法上鎖的方式,效率一樣低下。

    ③嘗試給重要代碼上鎖

    public class MyObject {
       private static MyObject myObject;
       private MyObject(){}
       public static MyObject getInstance(){
             if(myObject == null){          
                   synchronized (MyObject.class){
                          myObject = new MyObject();
                   }
             }
             return myObject;
       }
    }
    public class MyThread extends Thread {
        public void run(){
           System.out.println(MyObject.getInstance().hashCode());
       }
       
        public static void main(String [] args){
          MyThread t1 = new MyThread();
         MyThread t2 = new MyThread();
           MyThread t3 = new MyThread();
           
           t1.start();
           t2.start();
           t3.start();
       }
    }
    運行結果爲三個線程輸出的值不相同,並非單例的。

    這樣的上鎖方式雖然雖然提升了效率,可是仍有可能同時有多個線程進入if方法內部,等待執行同步代碼塊,所以獲取了多個對象。

    ④使用DCL雙檢查鎖機制

    public class MyObject {
       private static MyObject myObject;
       private MyObject(){}
       public static MyObject getInstance(){
             if(myObject == null){          
                   synchronized (MyObject.class){
                          if(myObject == null){
                                myObject = new MyObject();
                          }
                   }
             }
             return myObject;
       }
    }
    public class MyThread extends Thread {
        public void run(){
           System.out.println(MyObject.getInstance().hashCode());
       }
       
        public static void main(String [] args){
          MyThread t1 = new MyThread();
         MyThread t2 = new MyThread();
           MyThread t3 = new MyThread();
           
           t1.start();
           t2.start();
           t3.start();
       }
    }
    運行結果爲三個線程輸出的值相同。

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

相關文章
相關標籤/搜索