<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    我的家園

    我的家園

    狀態依賴的類--JCIP C14.1讀書筆記

    Posted on 2012-04-15 16:26 zljpp 閱讀(110) 評論(0)  編輯  收藏

    [本文是我對Java Concurrency In Practice C14.1的歸納和總結. ?轉載請注明作者和出處, ?如有謬誤, 歡迎在評論中指正. ]?

    java類庫中包含許多狀態依賴的類: 其中的某些方法只有滿足特定的前置條件才能繼續, 比如BlockingQueue的take方法, 只有隊列不為空時take方法才能返回.

    狀態依賴的操作一般如下:

    void blockingAction() {
    	申請鎖
    	while(前置條件不滿足) {
    		釋放鎖
    		重新獲取鎖
    	}
    	執行操作
    	釋放鎖
    }
    ?

    BaseBoundedBuffer是一個普通抽象類, 它對put和take方法的實現是有缺陷的: 沒有在put方法執行前判斷緩沖區是否已滿, 也沒有在take方法執行之前判斷緩沖區是否為空. 其代碼如下:

    public abstract class BaseBoundedBuffer<V> {
    	private final V[] buf;
    	private int tail;
    	private int head;
    	private int count;
    
    	@SuppressWarnings("unchecked")
    	protected BaseBoundedBuffer(int capacity) {
    		this.buf = (V[]) new Object[capacity];
    	}
    
    	protected synchronized final void doPut(V v) {
    		buf[tail] = v;
    		if (++tail == buf.length) {
    			tail = 0;
    		}
    		++count;
    	}
    
    	protected synchronized final V doTake() {
    		V v = buf[head];
    		buf[head] = null;
    		if (++head == buf.length) {
    			head = 0;
    		}
    		--count;
    		return v;
    	}
    
    	public synchronized final boolean isFull() {
    		return count == buf.length;
    	}
    
    	public synchronized final boolean isEmpty() {
    		return count == 0;
    	}
    }?

    本文將使用多種方式為doPut和doTake方法增加前置判斷.

    ?

    通知調用方前置條件判斷失敗

    GrumpyBoundedBuffer是BaseBoundedBuffer的子類, 并向外提供put和take方法. 調用put方法時, 如果緩沖區已滿, 將拋出BufferFullException異常. 調用take方法時, 如果緩沖區為空, 將拋出BufferEmptyException異常:

    public class GrumpyBoundedBuffer<V> extends BaseBoundedBuffer<V> {
    	public GrumpyBoundedBuffer(int size) {
    		super(size);
    	}
    
    	public synchronized void put(V v) throws BufferFullException {
    		if (isFull())
    			throw new BufferFullException();
    		doPut(v);
    	}
    
    	public synchronized V take() throws BufferEmptyException {
    		if (isEmpty())
    			throw new BufferEmptyException();
    		return doTake();
    	}
    }?

    GrumpyBoundedBuffer實現起來很簡單, 但是這樣的類很難使用: 調用方需要捕獲并處理異常. 例如調用take方法時需要這樣:

    public void invocaton() {
    	while (true) {
    		try {
    			V item = buffer.take();
    			// use item 
    			break;
    		} catch (BufferEmptyException e) {
    			// 當拋出BufferEmptyException異常時, 說明buffer為空. 調用方睡眠一段時間后再進行嘗試
    			Thread.sleep(SLEEP_GRANULARITY);
    		}
    	}
    }?

    這樣的調用方式是令人難以忍受的, 而且sleep的時間SLEEP_GRANULARITY不好確定: 如果設定的太短, 將白白消耗CPU資源. 如果設定的太長, 則程序的響應性不好, 也有可能錯過前置條件滿足的時刻.

    ?

    內部處理重試邏輯

    既然由調用方處理異常并重試是不可取的, 那么SleepyBoundedBuffer類改為在內部處理重試邏輯:

    public class SleepyBoundedBuffer<V> extends BaseBoundedBuffer<V> {
    	private static final long SLEEP_GRANULARITY = 10;
    
    	public SleepyBoundedBuffer(int size) {
    		super(size);
    	}
    
    	public void put(V v) throws InterruptedException {
    		while (true) {
    			synchronized (this) {
    				if (!isFull()) {
    					doPut(v);
    					return;
    				}
    			}
    			// 釋放鎖后sleep一段時間再進行重試
    			Thread.sleep(SLEEP_GRANULARITY);
    		}
    	}
    
    	public V take() throws InterruptedException {
    		while (true) {
    			synchronized (this) {
    				if (!isEmpty()) {
    					return doTake();
    				}
    			}
    			// 釋放鎖后sleep一段時間再進行重試
    			Thread.sleep(SLEEP_GRANULARITY);
    		}
    	}
    }

    SleepyBoundedBuffer相比于GrumpyBoundedBuffer具有很大的進步: 不需要在調用方進行重試. SleepyBoundedBuffer易于使用, 但是sleep的時間仍然不好確定, 需要在響應性和CPU消耗間權衡.?

    ?

    前置條件滿足時喚醒線程

    BoundedBuffer試著解決SleepyBoundedBuffer中的問題: 當前置條件不滿足時將線程掛起, 并等待前置條件滿足時由其他線程喚醒, 這樣就不需要權衡sleep的時間了:

    public class BoundedBuffer<V> extends BaseBoundedBuffer<V> {
    	public BoundedBuffer(int size) {
    		super(size);
    	}
    
    	public synchronized void put(V v) throws InterruptedException {
    		// 當緩沖區已滿時將線程掛起, 等待其他線程喚醒
    		// 不給喚醒之后再次判斷緩沖區是否已滿
    		while (isFull()) {
    			wait();
    		}
    		doPut(v);
    		// 操作完成后喚醒其他線程
    		notifyAll();
    	}
    
    	public synchronized V take() throws InterruptedException {
    		// 當緩沖區為空時將線程掛起, 等待其他線程喚醒
    		// 被喚醒之后再次判斷緩沖區是否為空
    		while (isEmpty()) {
    			wait();
    		}
    		V v = doTake();
    		// 操作完成后喚醒其他線程
    		notifyAll();
    		return v;
    	}
    }?

    BoundedBuffer已經比較完美了, 相比于SleepyBoundedBuffer, 其具有更好的響應性, 更高的CPU效率以及更少的上下文切換.

    ?






    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 亚洲a∨无码精品色午夜| 亚洲日本国产精华液| 国产亚洲精品成人久久网站| 成年人视频免费在线观看| 亚洲色欲www综合网| 美丽姑娘免费观看在线观看中文版| 亚洲精品成人网站在线观看| 国产一区二区三区免费观在线 | 国产网站在线免费观看| 亚洲综合无码一区二区痴汉| 成人毛片免费观看视频| 亚洲AV成人无码网站| 国产成人精品日本亚洲专区| AAA日本高清在线播放免费观看 | 亚洲一区二区影视| 成人免费视频一区| 高潮内射免费看片| 亚洲无人区一区二区三区| 亚洲视频在线观看免费| 亚洲欧洲日本在线观看 | 国产猛男猛女超爽免费视频| 亚洲国产精品久久久久网站| 特级做A爰片毛片免费69| 久久亚洲欧美国产精品| 亚洲人成网77777色在线播放| 99久久99久久精品免费观看| 亚洲免费福利在线视频| 亚洲av手机在线观看| 中文精品人人永久免费| 91亚洲精品麻豆| 日产国产精品亚洲系列| 性xxxxx大片免费视频| 亚洲男人天堂2018av| 青青草原亚洲视频| 69成人免费视频| 成人嫩草影院免费观看| 久久亚洲AV成人无码软件| 四虎国产精品免费久久影院| 日韩电影免费在线观看| 性色av极品无码专区亚洲| 亚洲国产精品无码av|