java並發編程實戰學習筆記之對象的組合與基礎構建模組
第四章 對象的組合4.1 構建安全的類4.2 執行個體封閉
@ThreadSafepublic class PersonSet { @GuardedBy("this") private final Set<Person> mySet = new HashSet<Person>(); public synchronized void addPerson(Person p) { mySet.add(p); } public synchronized boolean containsPerson(Person p) { return mySet.contains(p); } interface Person { }}
對personset的對象myset進行了封裝,但是person的安全性未知,也叫java監視器模式使用私人鎖來保護對象
public class PrivateLock { private final Object myLock = new Object(); @GuardedBy("myLock") Widget widget; void someMethod() { synchronized (myLock) { // Access or modify the state of widget } }}
4.3 執行緒安全性的委託不可變的域是安全執行緒的,可以被自由的共用與發布應用安全執行緒的容器來封裝類中的狀態域來實現安全執行緒,將類的安全***給底層的其他類去實現,就叫做執行緒安全性委託,但是如果存在多個相互依賴的組合對象時,還必須用鎖來實現安全性。4.4 在現有的安全執行緒類中添加功能1)在原始類中添加方法2)通過繼承來拓展原來的類3)通過一個輔助類來添加功能用戶端加鎖:
@NotThreadSafeclass 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; }}@ThreadSafeclass GoodListHelper <E> { public List<E> list = Collections.synchronizedList(new ArrayList<E>()); public boolean putIfAbsent(E x) { synchronized (list) { //list對象鎖對每個用戶端來講都是同一個 boolean absent = !list.contains(x); if (absent) list.add(x); return absent; } }}
上述第一個內建類是誰調用就是誰組合:
@ThreadSafepublic class ImprovedList<T> implements List<T> { private final List<T> list; /** * PRE: list argument is thread-safe. */ 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; }
將list引入作為自己的成員變數,此時的內建鎖就是該類的對象本身 第五章 基礎構建模組5.1 同步容器類:Vector Hashtable通過封裝,對每個公有方法都進行同步,使得每次只能有一個線程來訪問容器的狀態,將所有對容器狀態的訪問都序列化,效率很低。同步容器類都是安全執行緒的,但是需要自己加鎖來執行複雜的複合操作,比如迭代等。迭代過程中,如果有其他線程在修改該容器,則會出現錯誤。設計同步類容器時並沒有解決該問題,因此在使用中還是需要自己加鎖來避免異常。但是這會使得效率很低,因為整個迭代期間其他線程不得訪問,改進辦法為容器複製。提防另外一種隱藏迭代:“helloworld”+set;將調用set的toString()函數,在該函數裡面執行迭代,容器的hashcode和equals方法也會執行迭代。5.2 並發容器:concurrentHashMap CopeOnWriteArrayListconcurrentHashMap:並不是將每個方法都放在同一個鎖上同步並且同時只能有一個線程訪問容器,二十使用了更細粒度的分段鎖來實現更大程度的共用。其提供的迭代器不會拋出異常,因此不需要在迭代過程中加鎖。CopeOnWriteArrayList:用於替代同步list,迭代期間不需要加鎖和複製。每次修改時都會複製底層數組,修改結束後重新發布一個新的容器版本。5.3 阻塞隊列和生產者-消費者模式blockingQueue5.4 阻塞方法與中斷方法當在代碼中調用了一個將拋出interruptedException異常的方法時,自己就變成了一個可阻塞方法,在捕獲到interruptedException異常時,最明智的選擇是傳遞給調用者,即再次拋出interruptedException異常。如果不能拋出異常,則調用該線程的interrupt方法恢複中斷,上層代碼將看到引發了一個中斷。比如:
public class TaskRunnable implements Runnable { BlockingQueue<Task> queue; public void run() { try { processTask(queue.take()); } catch (InterruptedException e) { // restore interrupted status Thread.currentThread().interrupt(); } } void processTask(Task task) { // Handle the task } interface Task { }}
5.5 同步工具類閉鎖:countDownLatchfutureTask:非同步事件訊號量:counting semaphore柵欄:閉鎖用於等待事件,柵欄用於等待進程。柵欄可重設用於重複使用