国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

Java并發編程中構建自定義同步工具

2019-11-26 15:13:13
字體:
來源:轉載
供稿:網友

當Java類庫沒有提供適合的同步工具時,就需要構建自定義同步工具。

可阻塞狀態依賴操作的結構

復制代碼 代碼如下:

acquir lock on object state;//請求獲取鎖
while(precondition does not hold){//沒有滿足前提條件
   release lock;//先釋放鎖
   wait until precondition might hold;//等待滿足前提條件
   optionlly fail if interrupted or timeout expires;//因為中斷或者超時執行失敗
   reacquire lock;//重新嘗試獲取鎖
}
perform action//執行
   release lock;//釋放鎖

有界緩存實現基類示例

復制代碼 代碼如下:

public class BaseBoundBuffer<V> {
private final V[] buf;
private int tail;
private int head;
private int count;
@SuppressWarnings("unchecked")
public BaseBoundBuffer(int capacity) {
buf = (V[]) new Object[capacity];
}
public synchronized void doPut(V v) {
buf[tail] = v;
if (++tail == buf.length)
tail = 0;
count++;
}
public synchronized V doTake() {
V v = buf[head];

if (++head == buf.length)
head = 0;
count--;
return v;
}
public final synchronized boolean isFull() {
return count == buf.length;
}
public final synchronized boolean isEmpty() {
return count == 0;
}
}

阻塞實現方式一:拋異常給調用者

復制代碼 代碼如下:

public synchronized void put1(V v)  throws Exception{
if(isFull())
throw new Exception("full error");
doPut(v);
}

分析:異常應該應用于發生異常情況中,在這里拋異常不合適;需要調用者是處理前提條件失敗的情況,并沒有解決根本問題。
阻塞實現方式二:通過輪詢和休眠
復制代碼 代碼如下:

public void put2(V v) throws InterruptedException {
while (true) {//輪詢
synchronized (this) {
if (!isFull()) {
doPut(v);
return;    
}
}
Thread.sleep(SLEEP_TIME);//休眠
}
}

分析:很難權衡休眠時間SLEEP_TIME設置。如果設置過小,CPU可能會輪詢多次,消耗CPU資源也越高;如果設置過大,響應性就越低。

阻塞實現方式三:條件隊列

條件隊列中的元素是一個個等待相關條件的線程。每個Java對象都可以作為一個鎖,每個對象同樣可以作為一個條件隊列,并且Object中的wait、notify、notifyAll方法就構成了內部條件隊列的API。Object.wait會自動釋放鎖,并請求操作系統掛起當前線程,從而使其它線程能獲得這個鎖并修改對象的狀態。Object.notify和Object.notifyAll能喚醒正在等待線程,從條件隊列中選取一個線程喚醒并嘗試重新獲取鎖。

復制代碼 代碼如下:

public synchronized void put3(V v) throws InterruptedException {
while(isFull())
wait();
doput(v);
notifyAll();
}

分析:獲得較好響應,簡單易用。

使用條件隊列​
1.條件謂詞

1).定義:條件謂詞是使某個操作成為狀態依賴操作的前提條件。條件謂詞是由類中各個狀態變量構成的表達式。例如,對于put方法的條件謂詞就是“緩存不為空”。
2).關系:在條件等待中存在一種重要的三元關系,包括加鎖、wait方法和一個條件謂詞。在條件謂詞中包含多個狀態變量,而每個狀態變量必須由一個鎖來保護,因此在測試條件謂詞之前必須先持有這個鎖。鎖對象和條件隊列對象(及調用wait和notify等方法所在的對象)必須是同一個對象。
3).約束:每次調用wait都會隱式地和特定的條件謂詞相關聯,當調用特定條件謂詞時,調用者必須已經持有與條件隊列相關的鎖,這個鎖必須還保護這組成條件謂詞的狀態變量

2.條件隊列使用規則

1).通常都有一個條件謂詞
2).永遠在調用wait之前測試條件謂詞,并且在wait中返回后再次測試;
3).永遠在循環中調用wait;
4).確保構成條件謂詞的狀態變量被鎖保護,而這個鎖必須與這個條件隊列相關聯;
5).當調用wait、notify和notifyAll時,要持有與條件隊列相關聯的鎖;
6).在檢查條件謂詞之后,開始執行被保護的邏輯之前,不要釋放鎖;

3.通知

盡量使用notifyAll,而不是nofify.因為nofify會隨機喚醒一個線程從休眠狀態變為Blocked狀態(Blocked狀態是種線程一直處于嘗試獲取鎖的狀態,即一旦發現鎖可用,馬上持有鎖),而notifyAll會喚醒條件隊列中所有的線程從休眠狀態變為Blocked狀態.考慮這么種情況,假如線程A因為條件謂詞Pa進入休眠狀態,線程B因為條件謂詞Pb進入休眠狀態.這時Pb為真,線程C執行單一的notify.如果JVM隨機選擇了線程A進行喚醒,那么線程A檢查條件謂詞Pa不為真后又進入了休眠狀態.從這以后再也沒有其它線程能被喚醒,程序會一直處于休眠狀態.如果使用notifyAll就不一樣了,JVM會喚醒條件隊列中所有等待線程從休眠狀態變為Blocked狀態,即使隨機選出一個線程一因為條件謂詞不為真進入休眠狀態,其它線程也會去競爭鎖從而繼續執行下去.

4.狀態依賴方法的標準形式

復制代碼 代碼如下:

void stateDependentMethod throwsInterruptedException{
synchronized(lock){
while(!conditionPredicate))
lock.wait();
}
//dosomething();
....

notifyAll();
}

顯示Condition對象

顯示的Condition對象是一種更靈活的選擇,提供了更豐富的功能:在每個鎖上可以存在多個等待,條件等待可以是中斷的獲不可中斷的,基于時限的等待,以及公平的或非公平的隊列操作。一個Condition可以和一個Lock關聯起來,就像一個條件隊列和一個內置鎖關聯起來一樣。要創建一個Condition,可以在相關聯的Lock上調用Lock.newCondition方法。以下用顯示條件變量重新實現有界緩存

復制代碼 代碼如下:

public class ConditionBoundedBuffer<V> {
 private final V[] buf;
 private int tail;
 private int head;
 private int count;
 private Lock lock = new ReentrantLock();
 private Condition notFullCondition = lock.newCondition();
 private Condition notEmptyCondition = lock.newCondition();
 @SuppressWarnings("unchecked")
 public ConditionBoundedBuffer(int capacity) {
  buf = (V[]) new Object[capacity];
 }

 public void doPut(V v) throws InterruptedException {
  try {
   lock.lock();
   while (count == buf.length)
    notFullCondition.await();
   buf[tail] = v;
   if (++tail == buf.length)
    tail = 0;
   count++;
   notEmptyCondition.signal();
  } finally {
   lock.unlock();
  }

 }

 public V doTake() throws InterruptedException {
  try {
   lock.lock();
   while (count == 0)
    notEmptyCondition.await();
   V v = buf[head];
   buf[head] = null;
   if (++head == buf.length)
    head = 0;
   count--;
   notFullCondition.signal();
   return v;
  } finally {
   lock.unlock();
  }
 }
}

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 阳春市| 普陀区| 大城县| 花莲县| 阳江市| 大悟县| 饶河县| 德昌县| 灵台县| 社会| 宣汉县| 榆树市| 宜城市| 开阳县| 五华县| 普定县| 丘北县| 宝鸡市| 正镶白旗| 宜都市| 怀宁县| 昆山市| 历史| 龙州县| 新巴尔虎左旗| 桂东县| 宜昌市| 绥阳县| 区。| 呼和浩特市| 隆安县| 麦盖提县| 东山县| 广水市| 桐梓县| 肇州县| 长顺县| 当涂县| 屏边| 襄樊市| 琼海市|