JDK5新特性之線程阻塞隊列(四)
來源:程序員人生 發(fā)布時間:2014-11-19 08:42:32 閱讀次數(shù):2300次
1. 阻塞隊列和普通隊列:
隊列是1種基本的數(shù)據(jù)類型,其典型特點是先進先出。
阻塞隊列和普通隊列的區(qū)分在于:
當隊列為空時,從隊列中獲得元素的線程會被阻塞,直到其他的線程往空的隊列里插入新的元素;
當隊列是滿的時,往隊列里添加元素的操作會被阻塞,直到其他的線程從隊列移除1個或多個元素;

上圖中:線程1往阻塞隊列里添加元素,而線程2從阻塞隊列里移除元素
/**
* 阻塞隊列的簡單實現(xiàn)
*/
public class BlockingQueue<T> {
private List<T> queue = new LinkedList<T>();
private int limit = 10;
public BlockingQueue(){
}
public BlockingQueue(int limit) {
this.limit = limit;
}
// 入隊
public synchronized void enqueue(T obj) throws InterruptedException {
while (this.queue.size() == this.limit) {
wait();
}
if (this.queue.size() == 0) {
notifyAll();
}
this.queue.add(obj);
}
// 出隊
public synchronized Object dequeue() throws InterruptedException {
while (this.queue.size() == 0) {
wait();
}
if (this.queue.size() == this.limit) {
notifyAll();
}
return this.queue.remove(0);
}
}
2. API實現(xiàn):
BlockingQueue是1個接口,有以下實現(xiàn)類:
1. ArrayBlockQueue:1個由數(shù)組支持的有界阻塞隊列,此隊列遵守先進先出原則排序,創(chuàng)建其對象必須明確大小。
2. LinkedBlockQueue:1個可改變大小的阻塞隊列,此隊列遵守先進先出原則排序,創(chuàng)建其對象沒有明確大小,并發(fā)程序中,性能稍差。
3. PriorityBlockingQueue: 類似LinkedBlockQueue,但其所含對象的排序不是先進先出,而是根據(jù)對象的自然排序順序或構(gòu)造函數(shù)所帶的Comparator決定
4. SynchronousQueue:同步隊列, 每插入1個必須等待另外一個線程移除。
下面代碼用3個空間的隊列來演示阻塞隊列的功能和效果。
public class BlockingQueueTest {
public static void main(String[] args) {
// 阻塞隊列類: 隊列中可以存3個數(shù)據(jù)
final BlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(3);
// 開啟3個線程不斷的存數(shù)據(jù)
for (int i = 0; i < 3; i++) {
new Thread() {
public void run() {
while (true) {
try {
Thread.sleep((long) Math.random() * 1000);
System.out.println(Thread.currentThread().getName() + " 準備放數(shù)據(jù)!");
queue.put(1); // 往隊列中存數(shù)據(jù)
System.out.println(Thread.currentThread().getName()
+ " 已放了數(shù)據(jù),隊列目前有: " + queue.size() + " 個數(shù)據(jù)!");
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}.start();
}
// 開啟1個線程不斷的取數(shù)據(jù)
new Thread() {
public void run() {
while (true) {
try {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + " 準備取數(shù)據(jù)!");
queue.take(); // 從隊列中取數(shù)據(jù)
System.out.println(Thread.currentThread().getName()
+ " 已取走數(shù)據(jù),隊列目前有: " + queue.size() + " 個數(shù)據(jù)!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}.start();
}
}
Thread⑴ 準備放數(shù)據(jù)!
Thread⑴ 已放了數(shù)據(jù),隊列目前有: 1 個數(shù)據(jù)!
Thread-0 準備放數(shù)據(jù)!
Thread-0 已放了數(shù)據(jù),隊列目前有: 2 個數(shù)據(jù)!
Thread⑵ 準備放數(shù)據(jù)!
Thread⑵ 已放了數(shù)據(jù),隊列目前有: 3 個數(shù)據(jù)!
Thread⑶ 準備取數(shù)據(jù)!
Thread⑶ 已取走數(shù)據(jù),隊列目前有: 2 個數(shù)據(jù)!
Thread⑴ 準備放數(shù)據(jù)!
Thread⑴ 已放了數(shù)據(jù),隊列目前有: 3 個數(shù)據(jù)!
Thread-0 準備放數(shù)據(jù)!
Thread⑵ 準備放數(shù)據(jù)!
Thread⑶ 準備取數(shù)據(jù)!
Thread⑶ 已取走數(shù)據(jù),隊列目前有: 2 個數(shù)據(jù)!
Thread-0 已放了數(shù)據(jù),隊列目前有: 3 個數(shù)據(jù)!
Thread⑴ 準備放數(shù)據(jù)!
Thread-0 準備放數(shù)據(jù)!
Thread⑶ 準備取數(shù)據(jù)!
Thread⑶ 已取走數(shù)據(jù),隊列目前有: 2 個數(shù)據(jù)!
Thread⑵ 已放了數(shù)據(jù),隊列目前有: 3 個數(shù)據(jù)!
3. 阻塞隊列實現(xiàn)同步通訊
http://www.vxbq.cn/cxyms/題:子線程打印2行信息,然后主線程打印4行信息,循環(huán)各打印5次
public class BlockingQueueCommunication {
public static void main(String[] args) throws Exception {
final Business business = new Business();
// 子線程循環(huán)履行5次
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 1; i <= 5; i++) {
try {
business.sub(i);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}).start();
// 主線程循環(huán)履行5次
for (int i = 1; i <= 5; i++) {
business.main(i);
}
}
static class Business {
// 阻塞子線程的隊列,里面只能有1個數(shù)據(jù), 超了就會阻塞
BlockingQueue<Integer> subQueue = new ArrayBlockingQueue<Integer>(1);
// 阻塞主線程的隊列,里面只能有1個數(shù)據(jù), 超了就會阻塞
BlockingQueue<Integer> mainQueue = new ArrayBlockingQueue<Integer>(1);
// 這是1個匿名的構(gòu)造方法,創(chuàng)建對象的時候就會調(diào)用它
{
try {
System.out.println("我履行了,1上來就把main queue中放了1個數(shù)據(jù)");
mainQueue.put(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void sub(int i) throws Exception {
subQueue.put(1);
for (int j = 0; j <= 1; j++) {
System.out.println("sub thread sequence of " + j + " ,loop of " + i);
}
mainQueue.take(); // main線程釋放阻塞,開始運行
}
public void main(int i) throws Exception {
mainQueue.put(1);
for (int j = 0; j <= 3; j++) {
System.out.println("main thread sequence of " + j + " ,loop of " + i);
}
subQueue.take(); // sub線程釋放阻塞,開始運行
}
}
}
生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學(xué)習(xí)有所幫助,可以手機掃描二維碼進行捐贈