天天看點

并發 Collections.synchronizedList

[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]

繼續閱讀