package test;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 阻塞隊列簡單實現。
* 先進先出
*
* @author ZRD
* @since 2016-3-23 上午10:05:37
* @ClassName BlockingQueue
*/
public class BlockingQueue {
private Object[] data;//數據對象
private int count = 0;//當前數據對象中含有多少個數據
private int addPosition = 0;//當前add數據的索引位置
private int takePosition = 0;//當前take數據的索引位置
private Lock lock = new ReentrantLock();// 線程鎖
private Condition addCondition = lock.newCondition(); // 添加條件
private Condition takeCondition = lock.newCondition(); // 取出條件
public BlockingQueue(int size) {
data = new Object[size];
}
public void add(Object value) {
lock.lock();// 線程加鎖
try {
while (count == data.length) {// 隊列已經滿了
try {
//System.out.println("add await thread:" + Thread.currentThread().getName());
addCondition.await();// 該條件判斷如果線程檢測到隊列已滿,則全部進入等待。
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (addPosition == data.length) {// 判斷如果add索引位置等於size,則索引位置需要從0開始算起
addPosition = 0;
}
data[addPosition] = value;
/*
* 這裏會有個疑問?會不會把當前的位置原有的值給覆蓋?
* 不會,因爲當前只有一個線程進來,當add lock釋放前,先去通知take取值
*/
System.out.println("add:" + value + " add index:" + addPosition + " thread name:" + Thread.currentThread().getName());
addPosition++; //更新當前索引位置
count++;
takeCondition.signalAll();//喚醒take線程
} finally {
lock.unlock();//線程解鎖
}
}
public Object take() {
lock.lock();
Object value = null;
try {
while (count == 0) {
try {
//System.out.println("take await thread:" + Thread.currentThread().getName());
takeCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (takePosition == data.length) {
takePosition = 0;
}
value = data[takePosition];
System.out.println("take:" + value + " take index:" + takePosition + " thread name:" + Thread.currentThread().getName());
takePosition++;
count--;
addCondition.signalAll();
} finally {
lock.unlock();
}
return value;
}
/*
* Test main
*/
public static void main(String[] args) {
final BlockingQueue blockingQueue = new BlockingQueue(2);
/*
* 開啓5個線程同時往阻塞隊列裏面賦值。
* 因爲阻塞隊列裏面size=1,所以開啓5個線程每次只能有一個線程往裏面add數據,其他4個線程必須在等待
*/
for (int i = 0; i < 1000; i++) {
final int index = i;
new Thread(){
public void run() {
double value = Math.random();
//
blockingQueue.add(index);
};
}.start();
}
/*
* 爲了在多線程併發情況下,觀測add線程等待情況
* 休眠5s之後開啓新的線程從阻塞隊列裏面take
*/
try {
//Thread.sleep(5000);
} catch (Exception e) {
e.printStackTrace();
}
new Thread(){
public void run() {
while (true) {
// 從阻塞隊列裏面取值
Object value = blockingQueue.take();
}
};
}.start();
}
}
java 使用ReentrantLock Condition實現阻塞隊列
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.