一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務(wù)器之家 - 編程語言 - JAVA教程 - Java并發(fā)編程中構(gòu)建自定義同步工具

Java并發(fā)編程中構(gòu)建自定義同步工具

2019-12-16 13:19junjie JAVA教程

這篇文章主要介紹了Java并發(fā)編程中構(gòu)建自定義同步工具,本文講解了可阻塞狀態(tài)依賴操作的結(jié)構(gòu)、有界緩存實(shí)現(xiàn)基類示例、阻塞實(shí)現(xiàn)方式一:拋異常給調(diào)用者、阻塞實(shí)現(xiàn)方式二:通過輪詢和休眠、阻塞實(shí)現(xiàn)方式三:條件隊(duì)列等內(nèi)容

當(dāng)Java類庫沒有提供適合的同步工具時,就需要構(gòu)建自定義同步工具。

可阻塞狀態(tài)依賴操作的結(jié)構(gòu)

復(fù)制代碼代碼如下:

acquir lock on object state;//請求獲取鎖
while(precondition does not hold){//沒有滿足前提條件
   release lock;//先釋放鎖
   wait until precondition might hold;//等待滿足前提條件
   optionlly fail if interrupted or timeout expires;//因?yàn)橹袛嗷蛘叱瑫r執(zhí)行失敗
   reacquire lock;//重新嘗試獲取鎖
}
perform action//執(zhí)行
   release lock;//釋放鎖

 

有界緩存實(shí)現(xiàn)基類示例

 

復(fù)制代碼代碼如下:


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;
}
}

 

阻塞實(shí)現(xiàn)方式一:拋異常給調(diào)用者

復(fù)制代碼代碼如下:

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


分析:異常應(yīng)該應(yīng)用于發(fā)生異常情況中,在這里拋異常不合適;需要調(diào)用者是處理前提條件失敗的情況,并沒有解決根本問題。
阻塞實(shí)現(xiàn)方式二:通過輪詢和休眠

復(fù)制代碼代碼如下:

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

 

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

阻塞實(shí)現(xiàn)方式三:條件隊(duì)列

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

復(fù)制代碼代碼如下:

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


分析:獲得較好響應(yīng),簡單易用。

 

使用條件隊(duì)列?
1.條件謂詞

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

2.條件隊(duì)列使用規(guī)則

1).通常都有一個條件謂詞
2).永遠(yuǎn)在調(diào)用wait之前測試條件謂詞,并且在wait中返回后再次測試;
3).永遠(yuǎn)在循環(huán)中調(diào)用wait;
4).確保構(gòu)成條件謂詞的狀態(tài)變量被鎖保護(hù),而這個鎖必須與這個條件隊(duì)列相關(guān)聯(lián);
5).當(dāng)調(diào)用wait、notify和notifyAll時,要持有與條件隊(duì)列相關(guān)聯(lián)的鎖;
6).在檢查條件謂詞之后,開始執(zhí)行被保護(hù)的邏輯之前,不要釋放鎖;

3.通知

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

4.狀態(tài)依賴方法的標(biāo)準(zhǔn)形式

復(fù)制代碼代碼如下:


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

 

notifyAll();
}

 

顯示Condition對象

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

復(fù)制代碼代碼如下:


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();
  }
 }
}

 

 

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 99久久精品免费看国产 | 青青草99热久久 | 红楼影视h38bar在线线播放 | 男女性刺激爽爽免费视频 | 古代翁熄乩伦小说h | 果冻传媒九一制片厂 | 关晓彤被调教出奶水的视频 | 国产经典一区 | 青草青草视频 | 免费看男女污污完整版 | 日本老妇乱子伦中文视频 | 欧美精品99久久久久久人 | 关晓彤被调教出奶水的视频 | 国士李风起全文在线阅读 | 日韩中文字幕网站 | 大陆国产vs国产对白 | 男人猛进猛出女人下面视频 | 吉川爱美与黑人解禁 | 亚洲国产精品综合久久一线 | 娇妻被健身教练挺进小说阅读 | 亚洲第一网站免费视频 | 亚洲系列在线 | 青草草视频在线观看 | 亚洲欧美专区精品久久 | 欧美亚洲影院 | 日韩三及片 | 久久国产主播福利在线 | 91精品国产免费久久 | 99久久精品自在自看国产 | 亚洲AV无码A片在线观看蜜桃 | vod国产成人精品视频 | 成人小视频在线观看免费 | 91精品国产91热久久p | 亚洲上最大成网人站4438 | 男生同性视频twink在线 | eeuss免费快捷| 91无毒不卡 | 韩剧hd | 亚洲精品私拍国产福利在线 | 99日影院在线播放 | 色女阁|