說明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