使用ReentrantLock模擬簡單生產者和消費者問題
本文主要講述使用Java的ReentrantLock來實現模擬生產者-消費者的問題,主要經過以下5個過程來完成:
1. 生產商品,向存儲商品的數組中添加商品,該過程用ReentrantLock來加鎖。
2. 消費商品,從存儲商品的數組中消費商品,該過程同樣用ReentrantLock來加鎖。
3. 用一個生產線程來模擬進行生產商品的操作。
4. 用一個消費線程來模擬進行消費商品的操作。
5. 測試整個生產者-消費者問題的程序。
定義一個BoundedQueue類
BoundedQueue類主要有兩個方法add和reduce,對應模擬商品的生產和消費,代碼如下:
public class BoundedQueue<T> {
private Object[] products;//存儲生產商品的數組products
volatile int count;//數組products數組中已經存儲的商品數量
int addIndex, reduceIndex;
Lock lock=new ReentrantLock();
//notFull和notEmpty主要用於實現等待/通知功能
Condition notFull=lock.newCondition();
Condition notEmpty=lock.newCondition();
//對類BoundedQueue的初始化操作
public BoundedQueue(int size){
super();
products=new Object[size];
count=0;
addIndex=0;
reduceIndex=0;
}
//模擬生產者生產商品
public void add(T t) throws InterruptedException{
lock.lock();
try{
while(count==products.length)
notFull.await();//如果products數組已經裝滿,則生產線程進入等待隊列等待,釋放lock
products[addIndex]=t;
if(++addIndex==products.length)
addIndex=0;
count++;//products中增加一個新商品
notEmpty.signal();//products中有商品,對消費線程進行通知
}finally{
lock.unlock();//釋放lock
}
}
//模擬消費者消費商品
public T reduce() throws InterruptedException{
lock.lock();
try{
while(count==0)
notEmpty.await();//如果products數組存儲的商品爲空,則消費線程進入等待隊列等待,釋放lock
Object product=products[reduceIndex];//獲取的是Object類型需要強制類型轉換
if(++reduceIndex==products.length)
reduceIndex=0;
count--;//products中消費一個商品
notFull.signal();//products還未被沾滿,對生產線程進行通知
return (T)product;
}finally{
lock.unlock();//釋放lock
}
}
//獲取生產者線程
public Thread getProduceThread(BoundedQueue<T> boundedQueue, Object products[])
{
Producer<T> producer=new Producer(boundedQueue, products);
Thread produceThread=new Thread(producer,"produceThread");
return produceThread;
}
//獲取消費者線程
public Thread getConsumeThread(BoundedQueue<T> boundedQueue)
{
Consumer<T> consumer=new Consumer(boundedQueue);
Thread consumeThread=new Thread(consumer,"consumeThread");
return consumeThread;
}
}
利用線程來模擬生產者
模擬生產者的代碼如下:
class Producer<T> implements Runnable{
private BoundedQueue<T> boundedQueue;
private Object[] readyProducts;//準備進行生產的商品
//初始化Producer類
public Producer(BoundedQueue<T> boundedQueue, Object[] readyProducts) {
super();
this.boundedQueue = boundedQueue;
this.readyProducts=new Object[readyProducts.length];
for(int i=0;i<readyProducts.length;i++)
this.readyProducts[i]=readyProducts[i];
}
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<readyProducts.length;i++)
{
try {
boundedQueue.add((T) readyProducts[i]);
System.out.println(Thread.currentThread().getName()+" has produced ["+(T)readyProducts[i]+"]");//打印生產商品的信息
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//}
}
}
}
利用線程來模擬消費者
模擬消費者的代碼如下:
class Consumer<T> implements Runnable{
private BoundedQueue<T> boundedQueue;
private boolean on;//作爲開關來關閉消費線程
//初始化Consumer類
public Consumer(BoundedQueue<T> boundedQueue) {
super();
this.boundedQueue=boundedQueue;
this.on = true;
}
@Override
public void run() {
// TODO Auto-generated method stub
while(on)
{
try {
T product=boundedQueue.reduce();
System.out.println(Thread.currentThread().getName()+" has consumed ["+product+"]");//打印消費的商品信息
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void closeThread(){
on=false;
}
}
進行測試
測試代碼如下:
public static void main(String[] args) {
BoundedQueue<String> boundedQueue=new BoundedQueue<>(3);
String fruits[]=new String[]{"apple","banana","peach","watermelon","pear","grape"};
Thread produceThread=boundedQueue.getProduceThread(boundedQueue, fruits);
Thread consumeThread=boundedQueue.getConsumeThread(boundedQueue);
produceThread.start();
consumeThread.start();
}