1 概述
ArrayBlockingQueued是數(shù)組實(shí)現(xiàn)的線程安全的有界的阻塞隊(duì)列喜命。隊(duì)列按照先進(jìn)先出(FIFO)的原則對(duì)元素進(jìn)行排序。
通過以下關(guān)鍵詞分析我們來更深入理解ArrayBlockingQueue
1.1 如何理解“隊(duì)列”
隊(duì)列這個(gè)概念非常好理解。你可以把它想象成排隊(duì)買票,先來的先買匙瘪,后來的人只能站末尾厢呵,不允許插隊(duì)窝撵。先進(jìn)者先出,這就是典型的“隊(duì)列”襟铭。
相對(duì)于棧只支持兩個(gè)基本操作:入棧 push()和出棧 pop()碌奉,對(duì)于也只支持兩個(gè)操作入隊(duì) enqueue(),放一個(gè)數(shù)據(jù)到隊(duì)列尾部寒砖;出隊(duì) dequeue()赐劣,從隊(duì)列頭部取一個(gè)元素,因此隊(duì)列跟棧一樣哩都,也是一種操作受限的線性表數(shù)據(jù)結(jié)構(gòu)
1.2 如何理解“線程安全的”
在多線程情況下魁兼,會(huì)有多個(gè)線程同時(shí)操作隊(duì)列,這個(gè)時(shí)候就會(huì)存在線程安全問題漠嵌,線程安全的隊(duì)列我們叫作并發(fā)隊(duì)列.
那如何實(shí)現(xiàn)一個(gè)線程安全的隊(duì)列呢璃赡?
方式一
最簡單直接的實(shí)現(xiàn)方式是直接在 enqueue()、dequeue() 方法上加鎖献雅,但是鎖粒度大并發(fā)度會(huì)比較低碉考,同一時(shí)刻僅允許一個(gè)存或者取操作。
方式二
利用 CAS 原子操作挺身,可以實(shí)現(xiàn)非常高效的并發(fā)隊(duì)列侯谁。
1.3 阻塞隊(duì)列
阻塞隊(duì)列其實(shí)就是在隊(duì)列基礎(chǔ)上增加了阻塞操作。簡單來說,就是在隊(duì)列為空的時(shí)候墙贱,從隊(duì)頭取數(shù)據(jù)會(huì)被阻塞热芹。因?yàn)榇藭r(shí)還沒有數(shù)據(jù)可取,直到隊(duì)列中有了數(shù)據(jù)才能返回惨撇;如果隊(duì)列已經(jīng)滿了伊脓,那么插入數(shù)據(jù)的操作就會(huì)被阻塞,直到隊(duì)列中有空閑位置后再插入數(shù)據(jù)魁衙,然后再返回报腔。
1.4 有界隊(duì)列
有界隊(duì)列表示隊(duì)列中存儲(chǔ)數(shù)據(jù)是有限,如果隊(duì)列滿后在次向隊(duì)列中添加數(shù)據(jù)會(huì)失敗或阻塞剖淀。
2 實(shí)現(xiàn)一個(gè)"隊(duì)列"
我們知道了纯蛾,隊(duì)列跟棧一樣,也是一種抽象的邏輯存儲(chǔ)結(jié)構(gòu)纵隔。它具有先進(jìn)先出的特性翻诉,支持在隊(duì)尾插入元素,在隊(duì)頭刪除元素捌刮。如果要想實(shí)現(xiàn)一個(gè)隊(duì)列可以用數(shù)組來實(shí)現(xiàn)碰煌,也可以用鏈表來實(shí)現(xiàn),用數(shù)組實(shí)現(xiàn)的隊(duì)列叫作順序隊(duì)列绅作,用鏈表實(shí)現(xiàn)的隊(duì)列叫作鏈?zhǔn)疥?duì)列芦圾。
2.1 順序隊(duì)列
2.1.1 實(shí)現(xiàn)原理
比起棧的數(shù)組實(shí)現(xiàn),隊(duì)列的數(shù)組實(shí)現(xiàn)稍微有點(diǎn)兒復(fù)雜,復(fù)雜在哪呢棚蓄?對(duì)于棧來說堕扶,我們只需要一個(gè)棧頂指針就可以了碍脏。但是隊(duì)列需要兩個(gè)指針:一個(gè)是 head 指針梭依,指向隊(duì)頭;一個(gè)是 tail 指針典尾,指向隊(duì)尾役拴。結(jié)合下面這幅圖來理解。當(dāng) a钾埂、b河闰、c、d 依次入隊(duì)之后褥紫,隊(duì)列中的 head 指針指向下標(biāo)為 0 的位置姜性,tail 指針指向下標(biāo)為 4 的位置。
當(dāng)我們調(diào)用兩次出隊(duì)操作之后髓考,隊(duì)列中 head 指針指向下標(biāo)為 2 的位置部念,tail 指針仍然指向下標(biāo)為 4 的位置。
你肯定已經(jīng)發(fā)現(xiàn)了,隨著不停地進(jìn)行入隊(duì)儡炼、出隊(duì)操作妓湘,head 和 tail 都會(huì)持續(xù)往后移動(dòng)。當(dāng) tail 移動(dòng)到最右邊乌询,即使數(shù)組中還有空閑空間榜贴,
也無法繼續(xù)往隊(duì)列中添加數(shù)據(jù)了。這個(gè)問題該如何解決呢妹田?使用循環(huán)隊(duì)列
2.3 循環(huán)隊(duì)列
循環(huán)隊(duì)列唬党,顧名思義,它長得像一個(gè)環(huán)秆麸。原本數(shù)組是有頭有尾的初嘹,是一條直線。現(xiàn)在我們把首尾相連沮趣,扳成了一個(gè)環(huán)屯烦。
我們可以看到,圖中這個(gè)隊(duì)列的大小為 8房铭,當(dāng)前 head=4驻龟,tail=7。當(dāng)有一個(gè)新的元素 a 入隊(duì)時(shí)缸匪,我們放入下標(biāo)為 7 的位置翁狐。但這個(gè)時(shí)候,我們并不把 tail 更新為 8凌蔬,而是將其在環(huán)中后移一位露懒,到下標(biāo)為 0 的位置。當(dāng)再有一個(gè)元素 b 入隊(duì)時(shí)砂心,我們將 b 放入下標(biāo)為 0 的位置懈词,然后 tail 加 1 更新為 1。所以辩诞,在 a坎弯,b 依次入隊(duì)之后,循環(huán)隊(duì)列中的元素就變成了下面的樣子:
通過這樣的方法译暂,我們成功避免了數(shù)據(jù)搬移操作抠忘。但是循環(huán)隊(duì)列最關(guān)鍵的是,確定好隊(duì)空和隊(duì)滿的判定條件外永。
在用數(shù)組實(shí)現(xiàn)的非循環(huán)隊(duì)列中崎脉,隊(duì)滿的判斷條件是 tail == n,隊(duì)空的判斷條件是 head == tail伯顶。那針對(duì)循環(huán)隊(duì)列囚灼,如何判斷隊(duì)空和隊(duì)滿呢呛踊?
方式一
就像我圖中畫的隊(duì)滿的情況,tail=3啦撮,head=4谭网,n=8,所以總結(jié)一下規(guī)律就是:(3+1)%8=4赃春。多畫幾張隊(duì)滿的圖愉择,你就會(huì)發(fā)現(xiàn),當(dāng)隊(duì)滿時(shí)滿足以下公式 :(tail+1)%n=head织中。
當(dāng)隊(duì)列滿時(shí)锥涕,圖中的 tail 指向的位置實(shí)際上是沒有存儲(chǔ)數(shù)據(jù)的。所以狭吼,循環(huán)隊(duì)列會(huì)浪費(fèi)一個(gè)數(shù)組的存儲(chǔ)空間层坠。
3 ArrayBlockingQueue源碼解析
3.1 類結(jié)構(gòu)
3.2 實(shí)現(xiàn)原理
1 ArrayBlockingQueue使用循環(huán)數(shù)組實(shí)現(xiàn)順序隊(duì)列,
2 ArrayBlockingQueue內(nèi)部存在著一個(gè)可重入的鎖刁笙,當(dāng)出隊(duì)和入隊(duì)操作時(shí)首先要獲取同一把鎖來保證線程安全破花。數(shù)組實(shí)現(xiàn)的隊(duì)列出隊(duì)和入隊(duì)是要相互排斥的,因?yàn)閿?shù)組刪除元素需要對(duì)數(shù)據(jù)中元素進(jìn)行位移疲吸!
3 ArrayBlockingQueue內(nèi)部存在著一個(gè)可重入的鎖座每,同時(shí)此鎖生成二個(gè)等待隊(duì)列Condition(notFull,notEmpty) -- 生產(chǎn)者和消費(fèi)者模式
在入隊(duì)時(shí)需要獲取鎖摘悴,獲取鎖成功后會(huì)判斷隊(duì)列是否已滿(數(shù)組已滿)峭梳。如果隊(duì)列已滿會(huì)將當(dāng)前線程添加到notFull等待隊(duì)列中等待喚醒。如果隊(duì)列沒有滿則入隊(duì)蹂喻,并釋放notEmpty等待隊(duì)列中一個(gè)等待的線程葱椭。
在出隊(duì)時(shí)需要獲取鎖,獲取鎖成功后會(huì)判斷隊(duì)列是否為空(數(shù)組為空)口四。如果隊(duì)列為空會(huì)將當(dāng)前線程添加到notEmpty等待隊(duì)列中等待喚醒孵运。如果隊(duì)列不為空則出隊(duì),并釋放notFull等待隊(duì)列中一個(gè)等待的線程窃祝。
3.3 核心屬性
// 內(nèi)部數(shù)組
final Object[] items;
// 重入鎖
final ReentrantLock lock;
// 條件掐松,用于出隊(duì)等待隊(duì)列
private final Condition notEmpty;
// 條件踱侣,用于入隊(duì)等待隊(duì)列
private final Condition notFull;
// 出隊(duì)位置
int takeIndex;
// 入隊(duì)位置
int putIndex;
//隊(duì)列中元素?cái)?shù)量
int count;
3.4 構(gòu)造函數(shù)
//創(chuàng)建一個(gè)帶有給定的(固定)容量和默認(rèn)訪問策略的 ArrayBlockingQueue粪小。
public ArrayBlockingQueue(int capacity) {
this(capacity, false);
}
//創(chuàng)建一個(gè)具有給定的(固定)容量和指定訪問策略的 ArrayBlockingQueue。
//fair 用來表示獲取鎖的方式是否公平[(詳見ReentrantLock)](https://note.youdao.com/)
public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
this.items = new Object[capacity];
lock = new ReentrantLock(fair);
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}
//創(chuàng)建一個(gè)具有給定的(固定)容量和指定訪問策略的 ArrayBlockingQueue抡句,它最初包含給定 collection 的元素探膊,并以 collection 迭代器的遍歷順序添加元素。
public ArrayBlockingQueue(int capacity, boolean fair,
Collection<? extends E> c) {
this(capacity, fair);
//將指定容器中元素依此添加到隊(duì)列中
final ReentrantLock lock = this.lock;
//獲取獨(dú)占鎖待榔,成功返回逞壁,失敗則阻塞
lock.lock();
try {
int i = 0;
try {
//遍歷容器張的元素添加到隊(duì)列中
for (E e : c) {
//檢查添加數(shù)據(jù)不能為null,NullPointerException
checkNotNull(e);
items[i++] = e;
}
} catch (ArrayIndexOutOfBoundsException ex) {
throw new IllegalArgumentException();
}
count = i;
putIndex = (i == capacity) ? 0 : i;
} finally {
lock.unlock();
}
}
3.5 入隊(duì)操作
將指定的元素插入到此隊(duì)列的尾部(如果立即可行且不會(huì)超過該隊(duì)列的容量)流济,在成功時(shí)返回 true,如果此隊(duì)列已滿腌闯,則拋出 IllegalStateException绳瘟。
public boolean add(E e) {
if (offer(e)){
return true;
}else{
// 拋出異常...
}
}
將指定的元素插入到此隊(duì)列的尾部(如果立即可行且不會(huì)超過該隊(duì)列的容量),在成功時(shí)返回 true姿骏,如果此隊(duì)列已滿糖声,則返回 false。
public boolean offer(E e) {
//插入的元素是否為null分瘦,是拋出NullPointerException異常
checkNotNull(e);
final ReentrantLock lock = this.lock;
//獲取獨(dú)占鎖蘸泻,成功返回,失敗則阻塞
lock.lock();
try {
//如果隊(duì)列已滿嘲玫,則返回false悦施。
if (count == items.length){
return false;
}else {
//添加元素到隊(duì)列尾部
enqueue(e);
return true;
}
} finally {
//釋放鎖
lock.unlock();
}
}
//添加元素到隊(duì)列尾部
private void enqueue(E x) {
//獲取隊(duì)列中數(shù)組對(duì)象
final Object[] items = this.items;
//在items[putIndex]插入元素
items[putIndex] = x;
//putIndex向數(shù)組尾部循環(huán)移動(dòng)
if (++putIndex == items.length)
putIndex = 0;
//隊(duì)列元素?cái)?shù)量+1
count++;
//釋放notEmpty等待隊(duì)列中阻塞的線程
notEmpty.signal();
}
將指定的元素插入此隊(duì)列的尾部,如果該隊(duì)列已滿去团,則在到達(dá)指定的等待時(shí)間之前等待可用的空間抡诞,在成功時(shí)返回 true。
public boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException {
//插入的元素是否為null土陪,是拋出NullPointerException異常
checkNotNull(e);
//獲取等待的時(shí)間
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
//獲取獨(dú)占鎖沐绒,成功返回,失敗則阻塞旺坠,可響應(yīng)中斷
lock.lockInterruptibly();
try {
//如果隊(duì)列已滿乔遮,等待時(shí)間大于0。將當(dāng)前線程添加notFull等待隊(duì)列取刃,并到限時(shí)阻塞當(dāng)前線程
while (count == items.length) {
if (nanos <= 0)
return false;
nanos = notFull.awaitNanos(nanos);
}
//添加元素到隊(duì)列尾部
enqueue(e);
//成功返回true
return true;
} finally {
//釋放鎖
lock.unlock();
}
}
將指定的元素插入此隊(duì)列的尾部蹋肮,如果該隊(duì)列已滿,則等待可用的空間
public void put(E e) throws InterruptedException {
//插入的元素是否為null璧疗,是拋出NullPointerException異常
checkNotNull(e);
final ReentrantLock lock = this.lock;
//獲取鎖坯辩,失敗則阻塞,可響應(yīng)中斷崩侠。
lock.lockInterruptibly();
try {
//如果隊(duì)列已滿漆魔。將當(dāng)前線程添加notFull等待隊(duì)列,并阻塞當(dāng)前線程
while (count == items.length){
notFull.await();
}
//添加元素到隊(duì)列
enqueue(e);
} finally {
//釋放鎖
lock.unlock();
}
}
3.6 出隊(duì)操作
獲取并移除此隊(duì)列的頭却音,如果此隊(duì)列為空改抡,則返回 null。
public E poll() {
final ReentrantLock lock = this.lock;
//獲取鎖系瓢,失敗則阻塞阿纤。
lock.lock();
try {
//若隊(duì)列為空,則返回 null夷陋。
//若隊(duì)列不為空欠拾,返回隊(duì)列頭部元素
return (count == 0) ? null : dequeue();
} finally {
//釋放鎖
lock.unlock();
}
}
//返回隊(duì)列頭部元素
private E dequeue() {
//獲取數(shù)組對(duì)象
final Object[] items = this.items;
//獲取items[takeIndex]元素
E x = (E) items[takeIndex];
//將數(shù)組items[takeIndex]元素設(shè)置為null
items[takeIndex] = null;
//takeIndex向后循環(huán)移動(dòng)
if (++takeIndex == items.length)
takeIndex = 0;
//隊(duì)列數(shù)量--
count--;
if (itrs != null)
itrs.elementDequeued();
//釋放等待notFull等待隊(duì)列中阻塞的線程
notFull.signal();
//返回
return x;
}
獲取并移除此隊(duì)列的頭部胰锌,在指定的等待時(shí)間前等待可用的元素(如果有必要)。
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
//獲取等待的時(shí)間
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
//獲取鎖藐窄,失敗則阻塞资昧,可響應(yīng)中斷。
lock.lockInterruptibly();
try {
//如果隊(duì)列為空荆忍,等待時(shí)間大于0榛搔,將當(dāng)前線程添加notEmpty等待隊(duì)列,并限時(shí)阻塞當(dāng)前線程
while (count == 0) {
if (nanos <= 0)
return null;
nanos = notEmpty.awaitNanos(nanos);
}
//返回隊(duì)列頭部元素
return dequeue();
} finally {
//釋放鎖
lock.unlock();
}
}
獲取并移除此隊(duì)列的頭部东揣,在元素變得可用之前一直等待
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
//獲取鎖践惑,失敗則阻塞,可響應(yīng)中斷嘶卧。
lock.lockInterruptibly();
try {
//如果隊(duì)列為空尔觉,將當(dāng)前線程添加notEmpty等待隊(duì)列張,并阻塞當(dāng)前線程
while (count == 0){
notEmpty.await();
}
//返回隊(duì)列頭部元素
return dequeue();
} finally {
//釋放鎖
lock.unlock();
}
}
指定元素出隊(duì)
- 從此隊(duì)列中移除指定元素的單個(gè)實(shí)例
- 遍歷隊(duì)列數(shù)組中元素所有元素找到指定元素在數(shù)組的下標(biāo)
-
如果刪除元素剛好位置和takeIndex重合芥吟,直接刪除侦铜,takeIndex移動(dòng)
image -
刪除元素b剛好位置在takeIndex和putIndex之間,直接刪除钟鸵,并將數(shù)組向前平移钉稍。
image
public boolean remove(Object o) {
//刪除元素為null,直接返回失敗
if (o == null){
return false;
}
final Object[] items = this.items;
final ReentrantLock lock = this.lock;
//獲取鎖,失敗則阻塞
lock.lock();
try {
// 遍歷內(nèi)部數(shù)組的所有元素棺耍,從 takeIndex 開始贡未,找到刪除元素的下標(biāo)位置
for (int i = takeIndex, k = count; k > 0; i = inc(i), k--) {
if (o.equals(items[i])) {
//刪除指定下標(biāo)元素
removeAt(i);
return true;
}
}
return false;
} finally {
//釋放鎖
lock.unlock();
}
}
//刪除指定下標(biāo)元素
void removeAt(final int removeIndex) {
final Object[] items = this.items;
// 判斷是否在刪除元素的下標(biāo)是否和takeIndex重合
if (removeIndex == takeIndex) {
//清理takeIndex下標(biāo)中的元素
items[takeIndex] = null;
//移動(dòng)takeIndex
if (++takeIndex == items.length)
takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
} else {
// 當(dāng)和takeIndex不重合,刪除的下標(biāo)在takeIndex~putIndex之間蒙袍。
// 需要將 [(i+1) - putIndex ] 位置的元素俊卤,前移一位,通過覆蓋 i 位置的元素害幅,來達(dá)到刪除的效果消恍。
final int putIndex = this.putIndex;
for (int i = removeIndex;;) {
int next = i + 1;
if (next == items.length)
next = 0;
if (next != putIndex) {
items[i] = items[next];
i = next;
} else {
items[i] = null;
this.putIndex = i;
break;
}
}
count--;
if (itrs != null)
itrs.removedAt(removeIndex);
}
//釋放等待notFull等待隊(duì)列中阻塞的線程
notFull.signal();
}
4 ArrayBlockingQueue使用
4.1 ArrayBlockingQueue API
// 創(chuàng)建一個(gè)帶有給定的(固定)容量和默認(rèn)訪問策略的 ArrayBlockingQueue。
ArrayBlockingQueue(int capacity)
// 創(chuàng)建一個(gè)具有給定的(固定)容量和指定訪問策略的 ArrayBlockingQueue以现。
ArrayBlockingQueue(int capacity, boolean fair)
// 創(chuàng)建一個(gè)具有給定的(固定)容量和指定訪問策略的 ArrayBlockingQueue狠怨,它最初包含給定 collection 的元素,并以 collection 迭代器的遍歷順序添加元素邑遏。
ArrayBlockingQueue(int capacity, boolean fair, Collection<? extends E> c)
// 將指定的元素插入到此隊(duì)列的尾部(如果立即可行且不會(huì)超過該隊(duì)列的容量)佣赖,在成功時(shí)返回 true,如果此隊(duì)列已滿无宿,則拋出 IllegalStateException茵汰。
boolean add(E e)
// 自動(dòng)移除此隊(duì)列中的所有元素枢里。
void clear()
// 如果此隊(duì)列包含指定的元素孽鸡,則返回 true蹂午。
boolean contains(Object o)
// 移除此隊(duì)列中所有可用的元素,并將它們添加到給定 collection 中彬碱。
int drainTo(Collection<? super E> c)
// 最多從此隊(duì)列中移除給定數(shù)量的可用元素豆胸,并將這些元素添加到給定 collection 中。
int drainTo(Collection<? super E> c, int maxElements)
// 返回在此隊(duì)列中的元素上按適當(dāng)順序進(jìn)行迭代的迭代器巷疼。
Iterator<E> iterator()
// 將指定的元素插入到此隊(duì)列的尾部(如果立即可行且不會(huì)超過該隊(duì)列的容量)晚胡,在成功時(shí)返回 true,如果此隊(duì)列已滿嚼沿,則返回 false估盘。
boolean offer(E e)
// 將指定的元素插入此隊(duì)列的尾部,如果該隊(duì)列已滿骡尽,則在到達(dá)指定的等待時(shí)間之前等待可用的空間遣妥。
boolean offer(E e, long timeout, TimeUnit unit)
// 獲取但不移除此隊(duì)列的頭;如果此隊(duì)列為空攀细,則返回 null箫踩。
E peek()
// 獲取并移除此隊(duì)列的頭,如果此隊(duì)列為空谭贪,則返回 null境钟。
E poll()
// 獲取并移除此隊(duì)列的頭部,在指定的等待時(shí)間前等待可用的元素(如果有必要)俭识。
E poll(long timeout, TimeUnit unit)
// 將指定的元素插入此隊(duì)列的尾部慨削,如果該隊(duì)列已滿,則等待可用的空間套媚。
void put(E e)
// 返回在無阻塞的理想情況下(不存在內(nèi)存或資源約束)此隊(duì)列能接受的其他元素?cái)?shù)量理盆。
int remainingCapacity()
// 從此隊(duì)列中移除指定元素的單個(gè)實(shí)例(如果存在)。
boolean remove(Object o)
// 返回此隊(duì)列中元素的數(shù)量凑阶。
int size()
// 獲取并移除此隊(duì)列的頭部猿规,在元素變得可用之前一直等待(如果有必要)。
E take()
// 返回一個(gè)按適當(dāng)順序包含此隊(duì)列中所有元素的數(shù)組宙橱。
Object[] toArray()
// 返回一個(gè)按適當(dāng)順序包含此隊(duì)列中所有元素的數(shù)組姨俩;返回?cái)?shù)組的運(yùn)行時(shí)類型是指定數(shù)組的運(yùn)行時(shí)類型。
<T> T[] toArray(T[] a)
// 返回此 collection 的字符串表示形式师郑。
String toString()
4.2 案例
import java.util.*;
import java.util.concurrent.*;
/*
* ArrayBlockingQueue是“線程安全”的隊(duì)列环葵,而LinkedList是非線程安全的。
*
* 下面是“多個(gè)線程同時(shí)操作并且遍歷queue”的示例
* (01) 當(dāng)queue是ArrayBlockingQueue對(duì)象時(shí)宝冕,程序能正常運(yùn)行张遭。
* (02) 當(dāng)queue是LinkedList對(duì)象時(shí),程序會(huì)產(chǎn)生ConcurrentModificationException異常地梨。
*
*/
public class ArrayBlockingQueueDemo1{
// TODO: queue是LinkedList對(duì)象時(shí)菊卷,程序會(huì)出錯(cuò)缔恳。
//private static Queue<String> queue = new LinkedList<String>();
private static Queue<String> queue = new ArrayBlockingQueue<String>(20);
public static void main(String[] args) {
// 同時(shí)啟動(dòng)兩個(gè)線程對(duì)queue進(jìn)行操作!
new MyThread("ta").start();
new MyThread("tb").start();
}
private static void printAll() {
String value;
Iterator iter = queue.iterator();
while(iter.hasNext()) {
value = (String)iter.next();
System.out.print(value+", ");
}
System.out.println();
}
private static class MyThread extends Thread {
MyThread(String name) {
super(name);
}
@Override
public void run() {
int i = 0;
while (i++ < 6) {
// “線程名” + "-" + "序號(hào)"
String val = Thread.currentThread().getName()+i;
queue.add(val);
// 通過“Iterator”遍歷queue洁闰。
printAll();
}
}
}
}