多線程之 線程安全與非線程安全

多線程之 線程安全與非線程安全

 

  ArrayListVector有什麼區別?

  HashMapHashTable有什麼區別?

  StringBuilderStringBuffer有什麼區別

  這些都是Java面試中常見的基礎問題。面對這樣的問題,回答是:ArrayList是非線程安全的,Vector是線程安全的;HashMap是非線程安全的,HashTable是線程安全的;StringBuilder是非線程安全的,StringBuffer是線程安全的。

  此時如果繼續問:什麼是線程安全?線程安全和非線程安全有什麼區別?分別在什麼情況下使用?

線程安全:

  多個線程類併發操作某類的某個方法,(在該方法內部)修改這個類的某個成員變量的值,不會出錯,則我們就說,該的這個方法是線程安全的。

  某類的某方法是否線程安全的關鍵是:

  (1) 該方法是否修改該類的成員變量;

  (2) 是否給該方法加鎖(是否用synchronized關鍵字修飾)。 

線程不安全:

  多個線程類併發操作某類的某個方法,(在該方法內部)修改這個類的某個成員變量的值,很容易就會發生錯誤,故我們就說,這個方法是線程不安全的。如果要把這個方法變成線程安全的,則用 synchronized關鍵字來修飾該方法即可。

   注:用 synchronized關鍵字修飾方法,會導致加鎖,雖然可以使該方法線程安全,但是會極大的降低該方法的執行效率,故要慎用該關鍵字。

  

 

線程安全:

  多個線程()同時執行同一段代碼,就可能出現安全問題。

  看下面的代碼,來理解線程安全 

  public Double pi() {   
    int a = 22;   
    int b = 7;   
    return new Double(a / b);   
  }  

  現在在執行這個方法時,每一個線程都有自己的獨立的棧區。當線程進入到方法執行斷的時候,一個方法變量在方法代碼段中被創建,並保存在線程的棧區(靜態方法也放在這裏)。不同線程執行這段代碼時,會有不同的a/b變量。所以這裏是線程安全的,因爲沒有數據共享。 

  考慮下面的例子,多線程情況下只執行一次並可以重用結果: 

  private Double pi = null;   
  public Double pi() {   
    if (pi == null) {   
      pi = new Double(22 / 7);   
    }   
    return pi;   
  }   

  這個地方雖然優化了,但可惜他不是線程安全的。 

  兩個線程併發執行的時候同時進入到pi==null這個位置,這樣可能會new出一個髒的數據. 

 

  Consider this example which uses ThreadLocal to make the method pi() again thread-safe while still offering performance gains:  

  private static ThreadLocal pi = new ThreadLocal();   
  public Double pi() {   
    if (pi.get() == null) {   
      pi.set(new Double(22 / 7));   
    }     
    return (Double)pi.get();   
  }  
  ThreadLocal類封裝了任何類型對象,並把它綁定到當前線程。線程執行pi()方法的時候,實例pi返回的是當前線程的對象。這樣的調用是線程安全的。 
  Writing thread-safe code requires you to be careful when using instance variables or static variables, especially when you are modifying objects that may be used by other threads.   

 

  用 ArrayList還是 Vector二者如何取捨? 

  線程安全:指多線程操作同一個對象的某方法,修改該類的成員變量時,不會出現錯誤。 

  非線程安全:指多線程操作同一個對象的某方法,修改該類的成員變量時,可能會出現錯誤。 

  線程安全必須要使用很多synchronized關鍵字來同步控制,所以必然會導致性能的降低。 

  所以在使用的時候,如果是多個線程操作同一個對象,那麼使用線程安全的Vector;否則,就使用效率更高的ArrayList

 

非線程安全!=不安全 

  有人在使用過程中有一個不正確的觀點:我的程序是多線程的,不能使用ArrayList要使用Vector,這樣才安全。 

  非線程安全並不是多線程環境下就不能使用。注意上面有說到:多線程操作同一個對象。注意是同一個對象 

  比如最上面那個模擬,就是在主線程中new的一個ArrayList然後多個線程操作同一個ArrayList對象,就會有安全問題。 

  如果是每個線程中new一個ArrayList,而這個ArrayList只在這一個線程中使用,那麼肯定是沒安全問題的。

 

總結: 

  若多個線程同時修改某個外部傳來的對象的成員變量,很容易就會出現錯誤,我們稱之爲線程不安全。(該類的這個方法是線程不安全的。若要線程安全,用synchronized關鍵字修飾即可)

  

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章