【集合類型的併發】Collections.synchronizedList

    1 :關注要點,爲何在有synchroniezed方法的同時會出現 Collections.synchronizedListjava

    2 :知識背景: 您可能須要瞭解java Synchronized方法的加鎖的各類機制,包括如何上鎖,鎖對象
安全

    3 : plus: 您須要不斷的深化 Java加鎖的各類機制
dom


 

Java代碼  收藏代碼this

  1. @NotThreadSafe  spa

  2. class BadListHelper <E> {  線程

  3.     public List<E> list = Collections.synchronizedList(new ArrayList<E>());  orm

  4.   

  5.     public synchronized boolean putIfAbsent(E x) {  對象

  6.         boolean absent = !list.contains(x);  繼承

  7.         if (absent)  接口

  8.             list.add(x);  

  9.         return absent;  

  10.     }  

  11. }  

 

  這個示例但願實現的功能是爲List提供一個原子操做:若沒有則添加。由於ArrayList自己不是線程安全的,因此經過集合Collections.synchronizedList將其轉換爲一個線程安全的類,而後經過一個輔助的方法來爲List實現這麼個功能。初看起來這個方法沒問題,由於也添加了synchronized關鍵字實現加鎖了。

 

可是仔細分析,你會發現問題。首先對於synchronized關鍵字,須要說明的是,它是基於當前的對象來加鎖的,上面的方法也能夠這樣寫:

 

Java代碼  收藏代碼

  1. public boolean putIfAbsent(E x) {  

  2.     synchronized(this) {  

  3.         boolean absent = !list.contains(x);  

  4.         if (absent)  

  5.             list.add(x);  

  6.         return absent;  

  7.     }  

  8. }  

 

  因此這裏的鎖實際上是BadListHelper對象, 而能夠確定的是Collections.synchronizedList返回的線程安全的List內部使用的鎖絕對不是BadListHelper的對象,應爲你在聲明和初始化這個集合的過程之中,你尚且都不知道這個對象的存在。因此BadListHelper中的putIfAbsent方法和線程安全的List使用的不是同一個鎖,所以上面的這個加了synchronized關鍵字的方法依然不能實現線程安全性。

 

下面給出書中的另外一種正確的實現:

 

 

Java代碼  收藏代碼

  1. @ThreadSafe  

  2. class GoodListHelper <E> {  

  3.     public List<E> list = Collections.synchronizedList(new ArrayList<E>());  

  4.   

  5.     public boolean putIfAbsent(E x) {  

  6.         synchronized (list) {  

  7.             boolean absent = !list.contains(x);  

  8.             if (absent)  

  9.                 list.add(x);  

  10.             return absent;  

  11.         }  

  12.     }  

  13. }  

 

  若是你要分析這個實現是否正確,你須要搞清楚Collections.synchronizedList返回的線程安全的List內部使用的鎖是哪一個對象,因此你得看看Collections.synchronizedList這個方法的源碼了。該方法源碼以下:

 

Java代碼  收藏代碼

  1. public static <T> List<T> synchronizedList(List<T> list) {  

  2.     return (list instanceof RandomAccess ?  

  3.                 new SynchronizedRandomAccessList<T>(list) :  

  4.                 new SynchronizedList<T>(list));  

  5.     }  

 

 

經過源碼,咱們還須要知道ArrayList是否實現了RandomAccess接口:

 

Java代碼  收藏代碼

  1. public class ArrayList<E> extends AbstractList<E>  

  2.         implements List<E>, RandomAccess, Cloneable, java.io.Serializable  

 

  查看ArrayList的源碼,能夠看到它實現了RandomAccess,因此上面的synchronizedList放回的應該是SynchronizedRandomAccessList的實例。接下來看看SynchronizedRandomAccessList這個類的實現:

 

 

Java代碼  收藏代碼

  1. static class SynchronizedRandomAccessList<E>  

  2.     extends SynchronizedList<E>  

  3.     implements RandomAccess {  

  4.   

  5.         SynchronizedRandomAccessList(List<E> list) {  

  6.             super(list);  

  7.         }  

  8.   

  9.     SynchronizedRandomAccessList(List<E> list, Object mutex) {  

  10.             super(list, mutex);  

  11.         }  

  12.   

  13.     public List<E> subList(int fromIndex, int toIndex) {  

  14.         synchronized(mutex) {  

  15.                 return new SynchronizedRandomAccessList<E>(  

  16.                     list.subList(fromIndex, toIndex), mutex);  

  17.             }  

  18.         }  

  19.   

  20.         static final long serialVersionUID = 1530674583602358482L;  

  21.   

  22.         /** 

  23.          * Allows instances to be deserialized in pre-1.4 JREs (which do 

  24.          * not have SynchronizedRandomAccessList).  SynchronizedList has 

  25.          * a readResolve method that inverts this transformation upon 

  26.          * deserialization. 

  27.          */  

  28.         private Object writeReplace() {  

  29.             return new SynchronizedList<E>(list);  

  30.         }  

  31.     }  

 

由於SynchronizedRandomAccessList這個類繼承自SynchronizedList,而大部分方法都在SynchronizedList中實現了,因此源碼中只包含了不多的方法,可是經過subList方法,咱們能夠看到這裏使用的鎖對象爲mutex對象,而mutex是在SynchronizedCollection類中定義的,因此再看看SynchronizedCollection這個類中關於mutex的定義部分源碼:

Java代碼  收藏代碼

  1. static class SynchronizedCollection<E> implements Collection<E>, Serializable {  

  2.     // use serialVersionUID from JDK 1.2.2 for interoperability  

  3.     private static final long serialVersionUID = 3053995032091335093L;  

  4.   

  5.     final Collection<E> c;  // Backing Collection  

  6.     final Object mutex;     // Object on which to synchronize  

  7.   

  8.     SynchronizedCollection(Collection<E> c) {  

  9.             if (c==null)  

  10.                 throw new NullPointerException();  

  11.         this.c = c;  

  12.             mutex = this;  

  13.         }  

  14.     SynchronizedCollection(Collection<E> c, Object mutex) {  

  15.         this.c = c;  

  16.             this.mutex = mutex;  

  17.         }  

  18. }  

 能夠看到mutex就是當前的SynchronizedCollection對象,而SynchronizedRandomAccessList繼承自SynchronizedList,SynchronizedList又繼承自SynchronizedCollection,因此SynchronizedRandomAccessList中的mutex也就是SynchronizedRandomAccessList的this對象。因此在GoodListHelper中使用的鎖list對象,和SynchronizedRandomAccessList內部的鎖是一致的,因此它能夠實現線程安全性。

相關文章
相關標籤/搜索