说明1:假设有一个放商品的盘子(此盘子只能放下一个商品)。生产者每次生产一个商品之后,放到这个盘子里,然后唤醒消费者来消费这个面包。消费者消费完这个商品之后,就唤醒生产者生产下一个商品。前提是,只有盘子里没有商品时,生产者才生产商品,只有盘子里有商品时,消费者才来消费。因此第一个程序是一个“单生产” “单消费” 的问题。代码如下所示:
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:在多生产多消费问题中,我们假设有很多个盘子组成一个数组,生产者不停的生产商品(面包)往数组里面放,消费者不停的消费。当生产者判断已经所有盘子里都已经有面包时【注意,此处生产者判断所有盘子里都有面包,不是简单的判断生产的面包数目等于数组的长度这么简单,因为生产者在生产面包的同时,消费者也在消费面包,当生产者把生产的面包放到最后一个盘子里时,可能消费者已经消费了前面若干个面包了,所以此时并不满足所有盘子里都有面包。】生产者等待,唤醒一个消费者来消费。当消费者判断所有盘子里都没有面包时【注意:此处也不是简单的判断消费的面包数目等于数组长度这么简单,和上面的分析同理】消费者等待,唤醒一个生产者进行生产。多生产多消费的代码如下:
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(); } }
运行截图如下:
欢迎留言交流!