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

 

  ArrayListVector有什麼區別?面試

  HashMapHashTable有什麼區別?安全

  StringBuilderStringBuffer有什麼區別多線程

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

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

線程安全:性能

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

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

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

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

線程不安全:

  多個線程類併發操做某類的某個方法,(在該方法內部)修改這個類的某個成員變量的值,很容易就會發生錯誤,故咱們就說,這個方法是線程不安全的。若是要把這個方法變成線程安全的,則用 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關鍵字修飾便可)

  

相關文章
相關標籤/搜索