重用可以節(jié)省我們進行開發(fā)和測試(測試比我們自己測嚴(yán)謹(jǐn)?shù)囟?的時間和其他各種成本。
但是,對一個線程安全類進行擴展的時候就需要思考一些問題。
比如我們熟知的線程安全類Vector,該類中對所有的公有方法提供了synchronized修飾以保證訪問互斥與可見性。
但Vector畢竟是一個公有的結(jié)構(gòu),他對客戶代碼的不變性約束一無所知。
比如客戶代碼中對某個Vector對象連續(xù)調(diào)用了兩次方法,雖然每次都是線程安全的,但這種復(fù)合操作并不是一個原子操作,它可能不滿足我們的不變性約束,于是線程安全類變得"不安全"了。
對于一種數(shù)據(jù)結(jié)構(gòu)類,我們經(jīng)常做put-if-absent操作。
當(dāng)然,如果是在棧封閉或者是單線程應(yīng)用的情況下這沒什么問題。
但,如果是多線程訪問同一個數(shù)據(jù)結(jié)構(gòu)對象時我們就需要考慮這一操作是否是安全的?
即便我們使用的是所謂線程安全類。
于是我們會重用這個線程安全類,對其進行擴展,并保證我們的不變性約束不會受到破壞:
public class BetterVector <E> extends Vector<E> { static final long serialVersionUID = -3963416950630760754L; public synchronized boolean putIfAbsent(E x) { boolean absent = !contains(x); if (absent) add(x); return absent; }}也許是因為我們擴展的是JDK里面的Vector,所以會給人帶來一種安全感(除了有些規(guī)范中定義的同步策略,其余的情況誰都無法保證)。
但如果是你的同事提供的線程安全類呢? 誰都無法保證它不會在下一個版本時發(fā)生變化。
比較要命的是下一個版本中發(fā)生變化的偏偏是同步策略,這導(dǎo)致子類直接受影響。
我們需要想一個問題,如果不去繼承,我們?nèi)绾卧谥赜矛F(xiàn)有的線程安全類的情況下又保證自己的不變性約束?
于是我們想到了只使用需要的方法,既然繼承很危險,那我把線程安全對象作為field,把需要的功能拿過來用就可以了。
但下面是一個錯誤例子:
class BadListHelper <E> { public List<E> list = Collections.synchronizedList(new ArrayList<E>()); public synchronized boolean putIfAbsent(E x) { boolean absent = !list.contains(x); if (absent) list.add(x); return absent; }}不夠細(xì)心的話,給人的第一反應(yīng)就是:這沒問題吧....
確實,我們使用的list已經(jīng)用Collections.ysnchronizedList裝飾過,何況我們提供的putIfAbsent也加上了synchronized關(guān)鍵字,這個方法確實是同步的。
但是某個線程調(diào)用putIfAbsent的時候,另一個線程也可以調(diào)用其他方法。
這樣我們的不變性約束就被破壞,這個helper類變得毫無意義。
也就是說問題在于這個synchronized,我們要的不是synchronized(this),而是synchronized(list)。
因此helper應(yīng)該改為:
class GoodListHelper <E> { public List<E> list = Collections.synchronizedList(new ArrayList<E>()); public boolean putIfAbsent(E x) { synchronized (list) { boolean absent = !list.contains(x); if (absent) list.add(x); return absent; } }}到這一步已經(jīng)很不錯了,但是派生類和基類仍然存在一些耦合。
也許我們可以將list聲明為PRivate final,并提供一個構(gòu)造器,在構(gòu)造器里用Collections.ysnchronizedList進行裝飾。
但即使這樣仍存在行為上的耦合,我們不能針對基類的行為為其添磚加瓦。
于是我們可以使用組合來解決這一問題:
public class ImprovedList<T> implements List<T> { private final List<T> list; public ImprovedList(List<T> list) { this.list = list; } public synchronized boolean putIfAbsent(T x) { boolean contains = list.contains(x); if (contains) list.add(x); return !contains; } public int size() { return list.size(); } public boolean isEmpty() { return list.isEmpty(); } public boolean contains(Object o) { return list.contains(o); } public Iterator<T> iterator() { return list.iterator(); } public Object[] toArray() { return list.toArray(); } public <T> T[] toArray(T[] a) { return list.toArray(a); } public synchronized boolean add(T e) { return list.add(e); } public synchronized boolean remove(Object o) { return list.remove(o); } public boolean containsAll(Collection<?> c) { return list.containsAll(c); } public synchronized boolean addAll(Collection<? extends T> c) { return list.addAll(c); } public synchronized boolean addAll(int index, Collection<? extends T> c) { return list.addAll(index, c); } public synchronized boolean removeAll(Collection<?> c) { return list.removeAll(c); } public synchronized boolean retainAll(Collection<?> c) { return list.retainAll(c); } public boolean equals(Object o) { return list.equals(o); } public int hashCode() { return list.hashCode(); } public T get(int index) { return list.get(index); } public T set(int index, T element) { return list.set(index, element); } public void add(int index, T element) { list.add(index, element); } public T remove(int index) { return list.remove(index); } public int indexOf(Object o) { return list.indexOf(o); } public int lastIndexOf(Object o) { return list.lastIndexOf(o); } public ListIterator<T> listIterator() { return list.listIterator(); } public ListIterator<T> listIterator(int index) { return list.listIterator(index); } public List<T> subList(int fromIndex, int toIndex) { return list.subList(fromIndex, toIndex); } public synchronized void clear() { list.clear(); }}新聞熱點
疑難解答