java同步和互斥的应用:生产者消费者之爸爸妈妈儿子女儿苹果橘子编程实现

来源:互联网 发布:淘宝拍卖海关真的吗 编辑:程序博客网 时间:2024/05/19 23:56

转自:http://blog.csdn.net/chunqiuwei/article/details/7622008

 

一、转载原文

在《java 同步和互斥程序说明》这篇文章的基础上,来实现下面的程序

桌上有一个空盘子,只允许放一个水果。爸爸可以向盘中放苹果,也可以向盘中放桔子,儿子专等吃盘中的桔子,女儿专等吃盘中的苹果。规定当盘空时,一次只能放一只水果。

下面是程序的具体实现代码,在写这个程序的时候,有点小问题,纠结了很长时间,于是在csdn论坛上发表帖子终于得到了解决

先说说涉及到的类的作用,首先Fruits作为一个水果的父类,Apple和Orange是Fruits类的扩展类。CriticalResources类是临界资源类,作为缓冲区用,里面封装了数组大小为一的Fruits数组,可以看成“盘子”;ProducerOrange为生产橘子的类 ProducerApple为生产桔子的类 ConsumerApple(消费苹果的类) ConsumerOrange(消费桔子的类)

水果类代码如下

public class Fruits {private String name;public Fruits(String name) {this.name = name;}@Overridepublic String toString() {return name;}public Fruits() {super();}} 

 

苹果类:

public class Apple extends Fruits {public Apple(String name) {super(name);}public Apple() {// TODO Auto-generated constructor stub}}

桔子类:

public class Orange extends Fruits {public Orange(String name) {super(name);}public Orange() {// TODO Auto-generated constructor stub}}


 

下面是作为缓冲区盘子的代码
public class CriticalResources {private int index = 0;private static Fruits[] fruites = new Fruits[1];// 默认临界区有五个商品private ProducerApple pa = new ProducerApple(this);private ProducerOrange po = new ProducerOrange(this);private ConsumerApple ca = new ConsumerApple(this);private ConsumerOrange co = new ConsumerOrange(this);/** * 向临界资源里添加商品 利用synchronized关键字实现同步 添加后数组指针+1 * 如果临界资源数组里面装满了商品不能再生产,则生产线程等待以便让消费者消费 *  * @param goods */public synchronized void push(Fruits goods) {//while (this.index == this.fruites.length) {try {this.wait();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}this.notifyAll();// 唤醒生产者this.fruites[index++] = goods;}/** * 从临界资源里拿商品,先减一后返回 如果index==0说明, 临界资源数组里面没有商品,不能在消费 消费线程阻塞, 让生产者生产 则让生产者 *  * @return */public synchronized Fruits pop() {while (this.index == 0) {try {this.wait();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}this.notifyAll();// 唤醒消费者return fruites[--index];}/** * 看看是不是空了 *  * @return */public synchronized Fruits peek() {if (this.index == 0)return null;elsereturn fruites[index - 1];}public int getIndex() {return index;}public void setIndex(int index) {this.index = index;}public Fruits[] getFruites() {return fruites;}}

下面是生产桔子和消费桔子的代码

 

/** * 生产苹果的生产者 *  * @author Arthur *  */public class ProducerApple implements Runnable {private CriticalResources cr = null;// 封装一个临界资源对象,以便生产public ProducerApple(CriticalResources cr) {super();this.cr = cr;}private int count = 5;@Overridepublic void run() {while (count-- > 0)synchronized (cr) {while ((cr.peek() != null)) {try {cr.wait();// 缓冲区满,该生产者等待} catch (InterruptedException e) {e.printStackTrace();}}// 如果不加锁,此处容易被打断Fruits fruits = new Apple("苹果");cr.push(fruits);System.out.println("苹果生产商生产了" + fruits);cr.notifyAll();}}}


 

/** * 消费苹果的消费者 *  * @author Arthur *  */public class ConsumerApple implements Runnable {private CriticalResources cr = null;// 封装一个临界资源对象,以便消费public ConsumerApple(CriticalResources cr) {super();this.cr = cr;}int count = 5;@Overridepublic void run() { while(count-->0)            synchronized (cr) {                while (!(cr.peek() instanceof Apple) ) {                    try {                        cr.wait();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }                Fruits fruits = cr.pop();                System.out.println("----苹果消费者消费了-------" + fruits);                cr.notifyAll();                            }}}


 

桔子生产者与消费者代码:

public class ProducerOrange implements Runnable {CriticalResources cr = null;public ProducerOrange(CriticalResources cr) {super();this.cr = cr;}int count = 5; //做5次@Overridepublic void run() { while(count-->0)        synchronized (cr) {            while (cr.peek() != null) {                try {                    cr.wait();// 该生产这等待                } catch (InterruptedException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }            }            Fruits fruits = new Orange("橘子");            cr.push(fruits);            System.out.println("橘子生产商生产了" + fruits);            cr.notifyAll();        }}}


 

/** * 消费橘子的消费者 *  * @author Administrator *  */public class ConsumerOrange implements Runnable {private CriticalResources cr = null;// 封装一个临界资源对象,以便消费public ConsumerOrange(CriticalResources cr) {super();this.cr = cr;}int count = 5;@Overridepublic void run() {while (count-- > 0)// 如果缓冲区是苹果synchronized (cr) {while (!(cr.peek() instanceof Orange)) {try {cr.wait();// 该消费者等待} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}Fruits fruits = cr.pop();System.out.println("----橘子消费者消费了-------" + fruits);cr.notifyAll();}}}


 

 

客户端代码

public class Client {  /**     * @param args     */    public static void main(String[] args) {        CriticalResources cr = new CriticalResources();        // 生产苹果实例        ProducerApple appleP = new ProducerApple(cr);        // 消费苹果实例        ConsumerApple appleC = new ConsumerApple(cr);        // 橘子生产者实例        ProducerOrange orangeP = new ProducerOrange(cr);        // 橘子消费者实例        ConsumerOrange orangeC = new ConsumerOrange(cr);        // 生产苹果线程        Thread pThread = new Thread(appleP);        // 消费苹果线程        Thread cThread = new Thread(appleC);        // 生产橘子线程        Thread pt = new Thread(orangeP);        // 消费橘子线程        Thread ct = new Thread(orangeC);               pThread.start();        cThread.start();        pt.start();        ct.start();    }}

 

 

运行结果

苹果生产商生产了苹果
----苹果消费者消费了-------苹果
橘子生产商生产了橘子
----橘子消费者消费了-------橘子
苹果生产商生产了苹果
----苹果消费者消费了-------苹果
橘子生产商生产了橘子
----橘子消费者消费了-------橘子
苹果生产商生产了苹果
----苹果消费者消费了-------苹果
橘子生产商生产了橘子
----橘子消费者消费了-------橘子
苹果生产商生产了苹果
----苹果消费者消费了-------苹果
橘子生产商生产了橘子
----橘子消费者消费了-------橘子
苹果生产商生产了苹果
----苹果消费者消费了-------苹果
橘子生产商生产了橘子
----橘子消费者消费了-------橘子

================================================================================================================================

二、扩展

以上代码中的苹果生产者、消费者,桔子生产者、消费者的类中的run()函数中的每次循环都会调用

cr.notifyAll();

我试着把这代去掉,发现运行结果是:
苹果生产商生产了苹果----苹果消费者消费了-------苹果苹果生产商生产了苹果----苹果消费者消费了-------苹果苹果生产商生产了苹果----苹果消费者消费了-------苹果苹果生产商生产了苹果----苹果消费者消费了-------苹果苹果生产商生产了苹果----苹果消费者消费了-------苹果橘子生产商生产了橘子----橘子消费者消费了-------橘子橘子生产商生产了橘子----橘子消费者消费了-------橘子橘子生产商生产了橘子----橘子消费者消费了-------橘子橘子生产商生产了橘子----橘子消费者消费了-------橘子橘子生产商生产了橘子----橘子消费者消费了-------橘子

这是为什么呢?
(1) 我们先来看SDK对这个API的解释。
notifyAll用于唤醒在这个对象上等待的线程。一个线程通过调用等待方法来等待对象的监视器。
被唤醒的线程将会以和其它可能完成此对象的同步的线程相同的方式完成.
 for example, the awakened threads enjoy no reliable privilege or disadvantage in being the next thread to lock this object.
 
(2)网上资料:

   在java多线程编程中,就要涉及到了对于资源的访问,当多个线程同时访问一个资源的时候就要涉及到一种访问策略。java提供了锁的机制,就是一个线程访问这个资源的时候可以先把这个资源锁住可以用synchronized(the object)来锁定the object,其他访问这个资源的线程就进入阻塞状态,直到当前的线程执行了这个对象的notify或者notifyall其他访问这个对象的阻塞状态的线程才有可能变成就绪状态。其中notify是唤醒一个线程,而notifyall是唤醒所有阻塞进程。
 
原创粉丝点击