《多線程操做之生產者消費者》(單生產單消費&多生產多消費)

說明1:假設有一個放商品的盤子(此盤子只能放下一個商品)。生產者每次生產一個商品以後,放到這個盤子裏,而後喚醒消費者來消費這個麪包。消費者消費完這個商品以後,就喚醒生產者生產下一個商品。前提是,只有盤子裏沒有商品時,生產者才生產商品,只有盤子裏有商品時,消費者纔來消費。所以第一個程序是一個「單生產」  「單消費」 的問題。代碼以下所示:java

 

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

//描述資源  
//資源屬性:商品名稱和編號 
//行爲:對商品名稱賦值,獲取商品
class Resource{
	
	private String name;
	private int count = 1;

	// 定義標記
	private boolean flag = false; //初始標記爲假,代表盤子裏沒有商品(麪包)

	// 定義一個鎖對象
	private Lock lock = new ReentrantLock();

	//獲取鎖上的Condition對象	
	private Condition producer = lock.newCondition();//負責生產
	private Condition consumer = lock.newCondition();//負責消費 

	// 提供生產商品的方法
	public void set(String name) {
		lock.lock(); //獲取鎖
		try {
			while (flag) //當flag標記爲真時,說明盤子裏有商品(麪包)此時生產者等待,不然,生產商品
				try {
					producer.await();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			this.name = name + count;
			count++;
			System.out.println(Thread.currentThread().getName() + "...生產者..." + this.name);
			flag = true;
			// 喚醒一個消費者
			consumer.signal();
		} finally {//釋放鎖
			lock.unlock();
		}
	}

	//提供消費的方法
	public void out() {
		lock.lock(); //獲取鎖
		try {
			while (!flag) //當flag標記爲假時,說明盤子裏沒有商品(麪包),此時,消費者等待,不然,消費商品(麪包)
				try {
					consumer.await();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			System.out.println(Thread.currentThread().getName() + "...消費者..." + this.name);
			flag = false;
			//喚醒一個生產者
			producer.signal();
		} finally {//釋放鎖
			lock.unlock();
		}
	}
}

// 描述生產者
class Producer implements Runnable {
	// 生產者一初始化就要有資源
	private Resource r;

	public Producer(Resource r) {
		this.r = r;
	}

	@Override
	public void run() {
		while (true) {
			r.set("麪包");
		}
	}
}

// 描述消費者
class Consumer implements Runnable {
	// 消費者一初始化就要有資源
	private Resource r;

	public Consumer(Resource r) {
		this.r = r;
	}

	@Override
	public void run() {
		while (true) {
			r.out();
		}
	}
}

public class ProducerConsumer {
	public static void main(String[] args) {
		// 建立資源對象
		Resource r = new Resource();

		// 建立線程任務
		Producer pro = new Producer(r);
		Consumer con = new Consumer(r);

		// 建立線程對象(兩個生產者,兩個消費者)
		Thread t1 = new Thread(pro);
		Thread t2 = new Thread(pro);
		Thread t3 = new Thread(con);
		Thread t4 = new Thread(con);

		// 開啓線程
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}
}

 

  運行結果以下圖所示:(注意Ctrl+C結束程序)數組

說明2:在多生產多消費問題中,咱們假設有不少個盤子組成一個數組,生產者不停的生產商品(麪包)往數組裏面放,消費者不停的消費。當生產者判斷已經全部盤子裏都已經有面包時【注意,此處生產者判斷全部盤子裏都有面包,不是簡單的判斷生產的麪包數目等於數組的長度這麼簡單,由於生產者在生產麪包的同時,消費者也在消費麪包,當生產者把生產的麪包放到最後一個盤子裏時,可能消費者已經消費了前面若干個麪包了,因此此時並不知足全部盤子裏都有面包。】生產者等待,喚醒一個消費者來消費。當消費者判斷全部盤子裏都沒有面包時【注意:此處也不是簡單的判斷消費的麪包數目等於數組長度這麼簡單,和上面的分析同理】消費者等待,喚醒一個生產者進行生產。多生產多消費的代碼以下:ide

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class BoundedBuffer {
   final Lock lock = new ReentrantLock();//鎖
   final Condition notFull  = lock.newCondition(); //生產
   final Condition notEmpty = lock.newCondition(); //消費

   final Object[] items = new Object[100];//存儲商品的容器。
   int putptr/*生產者使用的角標*/, takeptr/*消費者使用的角標*/, count/*計數器*/;

	/*生產者使用的方法,往數組中存儲商品*/
   public void put(Object x) throws InterruptedException {
     lock.lock(); //獲取鎖
     try {
       while (count == items.length) //判斷計數器是否已到數組長度。滿了。
         notFull.await();//生產就等待。

       items[putptr] = x; //按照角標將商品存儲到數組中
	   System.out.println(Thread.currentThread().getName()+"...生產者..."+items[putptr]+"--->"+count);
		
       if (++putptr == items.length) //若是存儲的角標到了數組的長度,就將角標歸零。
			putptr = 0;
       ++count;//計數器自增。
       notEmpty.signal();//喚醒一個消費者
     } finally {
       lock.unlock();
     }
   }

	//消費者使用的方法
   public Object take() throws InterruptedException {
     lock.lock();
     try {
       while (count == 0) //若是計數器爲0,說明沒有商品,消費者等待。
         notEmpty.await();
       Object x = items[takeptr]; //從數組中經過消費者角標獲取商品。

       if (++takeptr == items.length) //若是消費的角標等於了數組的長度,將角標歸零。
		   takeptr = 0;
       --count;//計數器自減。
	   System.out.println(Thread.currentThread().getName()+"...消費者--->"+items[takeptr]+"..."+count);
       notFull.signal();//喚醒生產者。
       return x;
     } finally {
       lock.unlock();
     }
   } 
 }
 
//生產者
class Producer implements Runnable 
{
	//private int n = 1;
	private BoundedBuffer b;
	public Producer(BoundedBuffer b){
		this.b = b;
	}

	public void run(){
		while(true){
			try{
				b.put("麪包");
				//n++;
			}catch(InterruptedException e){}
			
		}
	}
}

//消費者
class Consumer implements Runnable 
{
	private BoundedBuffer b;
	public Consumer(BoundedBuffer b){
		this.b = b;
	}

	public void run(){
		while(true){
			try{
				b.take();
			}catch(InterruptedException e){}
			
		}
	}
}

//主函數
public class ThreadDemo12
{
	public static void main(String args[]){
		//建立資源對象
		BoundedBuffer b = new BoundedBuffer();

		//建立線程任務
		Producer pro = new Producer(b);
		Consumer con = new Consumer(b);

		//建立線程對象
		Thread t1 = new Thread(pro);
		Thread t2 = new Thread(pro);
		Thread t3 = new Thread(con);
		Thread t4 = new Thread(con);

		//開啓線程
		t1.start();
		t2.start();
		t3.start();
		t4.start();
	}
}

  運行截圖以下:函數

歡迎留言交流!this

相關文章
相關標籤/搜索