動手寫乙個阻塞佇列

2021-08-25 05:24:19 字數 2753 閱讀 1491

之前看佇列,都是停留在看和使用的階段。再次看佇列的時候,忽然發現並沒有深入到底層。比如:阻塞佇列時如何阻塞的呢?是監聽,還是等待呢?然後看著看著就看到了lock和reentrantlock,為什麼不使用synchronized呢?為什麼使用condition,condition是什麼呢?wait,notify,notifyall和await,signal,signalall有什麼區別呢?

能不能自己寫乙個阻塞佇列呢?

有時候是需要動手寫寫的,寫著寫著發現已經理解了,所以這裡就寫一下吧。

1.第一步,了解佇列容器

併發容器中有兩個比較常用的佇列容器,分別是arrayblockingqueue和linkedblockingqueue,

arrayblockingqueue內部是使用陣列實現了,linkedblockingqueue內部是使用鍊錶實現的。

陣列和鍊錶熟不熟悉呢?如果不熟悉,可不可以直接使用已經有的集合類實現呢?

所以本次嘗試著使用arraylist作為佇列容器。

2.第二步,了解佇列提供的方法

乙個佇列,起碼具有兩個方法:存和取。

所以這裡就定義兩個方法,add()往佇列中存資料,take()從佇列中取資料。

3.第三步,阻塞功能

take()方法應該具有阻塞功能,在沒有資料的時候處於等待狀態,在有資料的時候立刻可以從佇列中取出資料。

4.第四步,如何阻塞

可不可以設計成wait()和notify()呢?在take()方法如果取不出資料的時候呼叫wait()進行阻塞,在add()方法存資料的時候,呼叫notify()方法,喚醒wait()。嘿,貌似可以哈。

5.第五步,synchronized和reentrantlock

使用wait()和notify()方法貌似有些問題呢?

wait()和notify()需要和synchronized配合使用,wait()阻塞會釋放鎖,但是notify()卻不會釋放鎖。如果有乙個生產者一直占用著存方法,即使喚醒了wait()執行緒,那wait()執行緒也取不出資料,只有等到存方法執行完成,釋放了鎖,wait()才可以取資料。這個是有問題的,所以選擇得reentrantlock。

6.第六步,reentrantlock的condition

wait()和notify()都是資料object物件的方法,如果不能用,那該怎麼監聽呢?這時候需要用到condition物件,可以通過condition喚醒指定的某個執行緒。

7.第七步,開始寫自己的阻塞佇列

/**

* 仿照阻塞佇列,實現自己的阻塞佇列。

* 中間會使用到lock介面,reentrantlock,condition

*/public

class

******blockingqueue

//申明可中斷鎖,簡單起見也可以直接使用lock.lock(),lock.trylock()

lock.

lockinterruptibly()

;try

finally

}/**

* 從佇列中後去資料

* @return

* @throws interruptedexception

*/public integer take()

throws interruptedexception

}catch

(interruptedexception ie)

--count;

integer x = container.

get(0)

; system.out.

println

("取出方法取出元素:"

+x);

conditionfull.

signal()

;return x;

}finally

}}

8.第八步,測試

public

static

void

main

(string[

] args)

catch

(interruptedexception e)}}

; thread t2 =

newthread()

}catch

(interruptedexception e)}}

; t2.

start()

;try

catch

(interruptedexception e)

t1.start()

;}

執行結果:

佇列元素為空,進入阻塞...

新增元素:1

喚醒阻塞執行緒...

新增方法釋放鎖...

取出方法取出元素:1

取出方法釋放鎖...

佇列元素為空,進入阻塞...

新增元素:2

喚醒阻塞執行緒...

新增方法釋放鎖...

取出方法取出元素:1

取出方法釋放鎖...

佇列元素為空,進入阻塞...

到此,乙個簡單的阻塞佇列就完成了。

這裡只是簡單的實現了佇列的訪問和阻塞喚醒,很多的細節問題並沒有考慮。所以生產環境慎用,僅作為理解阻塞佇列原理的小練習。

手寫乙個佇列

佇列具有先進先出的特點,從隊尾新增元素,從隊首刪除元素。對於佇列,通常有兩種實現方式 陣列和鍊錶。package basicknowledge.集合框架.queue 基本功能 利用陣列實現乙個迴圈佇列 program summary author peicc create 2019 07 24 10...

Spring Boot 動手寫乙個 Start

我們在使用springboot 專案時,引入乙個springboot start依賴,只需要很少的 或者不用任何 就能直接使用預設配置,再也不用那些繁瑣的配置了,感覺特別神奇。我們自己也動手寫乙個start.pom 檔案如下 org.springframework.bootgroupid sprin...

Spring Boot 動手寫乙個 Start

我們在使用springboot 專案時,引入乙個springboot start依賴,只需要很少的 或者不用任何 就能直接使用預設配置,再也不用那些繁瑣的配置了,感覺特別神奇。我們自己也動手寫乙個start.pom 檔案如下 org.springframework.bootgroupid sprin...