ArrayList和Vector有什麼區別?面試
HashMap和HashTable有什麼區別?安全
StringBuilder和StringBuffer有什麼區別? 多線程
這些都是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關鍵字修飾便可)。