多线程经典问题——生产者消费者(Java实现)

生产者消费者是多线程的一个经典问题,在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度。生产者消费者描述的是有一块缓冲区作为仓库,生产者可以将产品放入仓库,消费者则可以从仓库中取走产品,即生产者和消费者在同一个时间段内共用同一个存储空间。如果在正常情况下不加以协调,当存储空间已满,生产者占用着它,消费者等着生产者让出空间从而拿走产品,生产者等着消费者消费产品,从而向空间中添加产品。互相等待,从而发生死锁。

解决生产者消费者问题的方法一般采用同步机制保证生产者和消费者之间的同步,这种方式有较高的效率,并且易于实现,代码的可控制性较好,属于常用的模式。

同步问题核心在于:如何保证同一资源被多个线程并发访问时的完整性。常用的同步方法是采用信号或加锁机制,保证资源在任意时刻至多被一个线程访问。Java语言在多线程编程上实现了完全对象化,提供了对同步机制的良好支持。

生产者与消费者模型中,要保证以下几点:

  1.  同一时间内只能有一个生产者生产 生产方法加锁sychronized
  2.  同一时间内只能有一个消费者消费 消费方法加锁sychronized
  3. 共享空间空时消费者不能继续消费 消费前循环判断是否为空,空的话将该线程wait,释放锁允许其他同步方法执行
  4. 共享空间满时生产者不能继续生产 生产前循环判断是否为满,满的话将该线程wait,释放锁允许其他同步方法执行

生产者模型:一直生产,直到生产完10个。在生产过程中,如果库存中存满(1个)则停止生产(由clerk控制)

public class Producer implements Runnable {
    private Clerk clerk;

    public Producer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        System.out.println("生产者生产中...");
        for (int product = 1; product <= 1000; product++) {
            try {
                clerk.setProdect(product);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

消费者模型:不断消费,直到消费10个。消费过程中,如果库存有货则消费,没货等待(clerk中wait())

public class Consumer implements Runnable {
    private Clerk clerk;

    public Consumer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        System.out.println("消费者购买中...");
        for (int i = 1; i <= 1000; i++) {
            try {
                clerk.getProdect();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

售货员模型: 负责控制库存,如果库存没货:通知生产者开始生产(notify), 并且通知消费者等待(wait)如果库存有货:通知生产者停止生产(wait),并且通知消费者开始消费(notify)。notify() / notifyall() :通知 实质上相当于 唤醒。加synchronized 为了保证,同一时刻只有一个生产者在生产,只有一个消费者在消费 。

public class Clerk {
    private int product = -1;

    public synchronized void setProdect(int product) throws InterruptedException {
        waitIfFull(); //如果满,等待   被唤醒后继续执行
        this.product = product;
        System.out.println("生产者生产 :" + product);
        notify();
    }
    public synchronized int getProdect() throws InterruptedException {
        waitIfEmpty(); //如果空,等待  被唤醒后继续执行
        int p = this.product;
        System.out.println("消费者获取 :" + p);
        this.product = -1;
        notify();
        return p;
    }

    private synchronized void waitIfEmpty() throws InterruptedException {
        if(product == -1){
            System.out.println("~~~~~~~消费者等待");
            wait();
        }
    }
    private synchronized void waitIfFull() throws InterruptedException {
        if(product != -1){
            System.out.println("~~~~~~~生产者等待");
            wait();
        }
    }
}

主类:

/**
 * Created by Amy on 2018/7/22.
 */
public class Demo_ProducerComsumer {
    public static void main(String[] args) {
        Clerk clerk = new Clerk();
        new Thread(new Producer(clerk)).start();
        new Thread(new Consumer(clerk)).start();
    }
}

结果如下:

以上就是简单生产者消费者模型。

参考文章:

https://blog.csdn.net/Dextrad_ihacker/article/details/53192046

http://www.cnblogs.com/0201zcr/p/4758533.html

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值