[quote]
1 :關注要點,為什麼在有synchroniezed方法的同時會出現 Collections.synchronizedList
2 :知識背景: 您可能需要了解java Synchronized方法的加鎖的各種機制,包括如何上鎖,鎖對象
3 : plus: 您需要不斷的深化 Java加鎖的各種機制
Java代碼
[email protected]
2.class BadListHelper <E> {
3. public List<E> list = Collections.synchronizedList(new ArrayList<E>());
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代碼 收藏代碼
[email protected]
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.
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内部的鎖是一緻的,是以它可以實作線程安全性。
[/quote]