所謂的執行緒安全問題

葉思維發表於2016-10-30

難道我們只能單純的背java的那個類是執行緒安全的,那個類不是執行緒安全的麼?
這和授人以魚有何區別呢?難道就沒有一種方法授人以漁?直接教我們如何去判斷一個類是否是執行緒安全的?
java中的執行緒安全是什麼:
就是執行緒同步的意思,就是當一個程式對一個執行緒安全的方法或者語句進行訪問的時候,其他的不能再對他進行操作了,必須等到這次訪問結束以後才能對這個執行緒安全的方法進行訪問
什麼叫執行緒安全:
如果你的程式碼所在的程式中有多個執行緒在同時執行,而這些執行緒可能會同時執行這段程式碼。如果每次執行結果和單執行緒執行的結果是一樣的,而且其他的變數的值也和預期的是一樣的,就是執行緒安全的。 
或者說:一個類或者程式所提供的介面對於執行緒來說是原子操作或者多個執行緒之間的切換不會導致該介面的執行結果存在二義性,也就是說我們不用考慮同步的問題。
執行緒安全問題都是由全域性變數及靜態變數引起的。
若每個執行緒中對全域性變數、靜態變數只有讀操作,而無寫操作,一般來說,這個全域性變數是執行緒安全的;若有多個執行緒同時執行寫操作,一般都需要考慮執行緒同步,否則就可能影響執行緒安全。
看過vector原始碼的同學就會知道他的許多操作都是加了synchronized修飾的比如他的新增元素。(不知道synchronized是什麼意思的自行百度!)

1
2
3
public synchronized void addElement(E obj) {  modCount++;
       ensureCapacityHelper(elementCount + 1);  elementData[elementCount++] = obj;
}

而HashMap的所有操作都沒有加synchronized修飾 ,不如他的put原始碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public V put(K key, V value) {
     if (key == null)
         return
      putForNullKey(value);
      int hash = hash(key.hashCode());
      int i = indexFor(hash, table.length);
      for(Entry<K,V> e = table[i]; e != null; e = e.next) {
         Object k;
         if (e.hash == hash &&((k = e.key) == key || key.equals(k))) {
             V oldValue = e.value;
             e.value = value;
             e.recordAccess(this);
             return
             oldValue;    }
     }
     modCount++;
     addEntry(hash, key, value, i);
     return null;
 }

再看看ArrayList的add方法的原始碼

1
2
3
4
5
public boolean add(E e) {
     ensureCapacity(size + 1);  // Increments modCount!!
     elementData[size++] = e;
     return true;
 }

再看StringBuffer的append原始碼,他是有synchronized修飾的

1
2
3
4
5
public synchronized
  StringBuffer append(String str) {
     super.append(str);
     return this;
 }

最後是Properties的setProperty方法,他是有synchronized修飾的

1
2
3
4
5
public synchronized
  Object setProperty(String key, String value) {
      return
      put(key, value);
 }

由此就可以判斷出誰是執行緒安全的了。

相關文章