java 使用ReentrantLock Condition實現阻塞隊列

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章