java併發編程實戰------閱讀筆記第五章基礎構建模塊

1、同步容器類 一、早期的同步容器類Vector ,Hashtable,相似於Collections.synchronizedXxxx方法建立的,就是用裝飾器模式把線程不安全的容器類包裝起來,全部公共方法都進行同步,這種容器性能較低。數組

二、同步容器來的問題(複合操做依然會致使混亂的結果) Vector是線程安全的,只是說明Vector自己不會被併發操做破壞,但這不等於併發操做就沒有問題。例如以下兩個方法被多線程操做:安全

public static Object getLast(Vector list){
		//第一步
                int lastIndex = list.size() - 1;
                //第二步
		return list.get(lastIndex);
	}
	
	public static void deleteLast(Vector list){
                //第一步
		int lastIndex = list.size() - 1;
                //第二步
		list.remove(lastIndex);
	}

線程A執行第一步完,還沒有執行第二步;線程B執行了第一步,再執行第二步完;以後線程A再執行第二步,這個時序就會出現問題集合元素個數變了而線程A不知道,會跑出數組越界異常,由於這些操做不是原子性。經過給被操做容器類加鎖能夠把這些複合操做變成原子操做(但其實Vector狀態沒有被破壞):多線程

public static Object getLast(Vector list){
		synchronized(list){
			int lastIndex = list.size() - 1;
			return list.get(lastIndex);
		}
		
	}
	
	public static void deleteLast(Vector list){
		synchronized(list){
			int lastIndex = list.size() - 1;
			list.remove(lastIndex);
		}

迭代操做也會出現多線程操做致使混亂的問題,在迭代操做上加鎖保護起來解決問題,可是下降了併發性。併發

//可能會被多線程操做而混亂結果,由於迭代是複合操做,不是原子操做		
for(int i = 0;i < vector.size();i++){
			//TODO
		}
//加鎖鎖住這個vector便可,可是下降了併發性,其餘線程不能操做vector
synchronized(vector){
			for(int i = 0;i < vector.size();i++){
			//TODO
			}
		}

迭代器與ConcurrentModificationException:即便是同步容器類也沒有考慮併發修改問題,對應策略是'fail-fast'快速失敗,當發現容器被修改時就拋出異常。改善這種狀況能夠在迭代時對容器進行克隆,迭代副本。 給容器加鎖來進行迭代涉及面太廣了,不合適,並且有些迭代器操做是隱藏的,容易被忽視。dom

public class HiddenIteratro {
	
	@GuardedBy("this")
	private final Set<Integer> set = new HashSet<Integer>();
	
	public synchronized void add(Integer i) { set.add(i); }
	public synchronized void remove(Integer i) { set.remove(i); }
	
	public void addTenThings(){
		Random r = new Random();
		for(int i=0;i<10;i++)
			add(r.nextInt());
		System.out.println("DEBUG: added ten elements to " + set);
	}

}

容器的hashCode和equals方法,將容器總體放入其餘容器,containsAll、removeAll、retainAll等等方法,以及把容器做爲參數的構造函數,都會隱含對容器進行迭代,這些迭代都有可能拋出ConcurrentModificationException。函數

2、併發容器 一、ConcurrentHashMap,使用了分段鎖,能夠支持任意數量的讀線程操做Map;支持多個讀線程和寫入線程操做Map;能夠支持必定數量寫入線程同時操做Map,迭代操做不會加鎖,採用了弱一致性而不是快速失敗,提升了併發性和吞吐量。併發Map還提供了一些複合原子操做,好比存在則刪除,存在則替換,不存在則插入等等。 二、CopyOnWriteList,CopyOnWriteHashSet:支持併發操做,迭代不會加鎖。工具

3、阻塞隊列和生產者消費者模型 生產者消費者模型的阻塞隊列實現了可變對象的線程封閉:開始是隻有放入對象的生產者線程能訪問可變對象,放入以後生產者再也不訪問可變對象;後面是隻有消費者線程能夠訪問可變對象,實現了可變對象在線程之間安全的傳遞。性能

4、阻塞方法或者中斷方法 等待I/O操做結束,等待鎖,等待Thread.sleep方法中醒來,等待另外一個線程的計算結果(Blocked,Waiting,Timed_Waiting)。方法拋出受檢查異常InterruptedException,說明該方法是一個阻塞方法,若是這個方法被中斷,它將努力提早結束阻塞狀態。拋出該異常後有兩個處理策略: 傳遞異常; 恢復中斷狀態。this

5、同步工具類 一、閉鎖(CountDownLatch):countDown方法遞減計數器,await方法等待計數器達到零。 二、FutureTask:也能夠用做閉鎖,FutureTask有三種狀態Waiting to run , running , Completed(完成包括正常結束、因爲取消而結束、因爲異常而結束)。 三、計數信號量(Counting Semaphore),控制同時訪問某個特定資源的操做數量,還可用來實現某種資源池,或者對容器施加邊界。線程

相關文章
相關標籤/搜索