生产者消费者案例java代码

大纲:java线程知识体系

一、概念

生产者消费者问题也称有限缓冲问题(Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了共享固定大小缓冲区的两个线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。 要解决该问题,就必须让生产者在缓冲区满时休眠(要么干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。通常采用进程间通信的方法解决该问题。如果解决方法不够完善,则容易出现死锁的情况。出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己。该问题也能被推广到多个生产者和消费者的情形。

二、问题分析

  • 在缓冲区为空时,消费者不能再进行消费
  • 在缓冲区为满时,生产者不能再进行生产
  • 在一个线程进行生产或消费时,其余线程不能再进行生产或消费等操作,即保持线程间的同步
  • 注意条件变量与互斥锁的顺序

在这里插入图片描述
由于前两点原因,因此需要保持线程间的同步,即一个线程消费(或生产)完,其他线程才能进行竞争CPU,获得消费(或生产)的机会。对于这一点,可以使用条件变量进行线程间的同步:生产者线程在product之前,需要wait直至获取自己所需的信号量之后,才会进行product的操作;同样,对于消费者线程,在consume之前需要wait直到没有线程在访问共享区(缓冲区),再进行consume的操作,之后再解锁并唤醒其他可用阻塞线程。
在访问共享区资源时,为避免多个线程同时访问资源造成混乱,需要对共享资源加锁,从而保证某一时刻只有一个线程在访问共享资源。

/*
解题思路
1、分清资源类和线程类 => 资源类是将其封装成Clerk类,由Clerk操作共享资源。线程类分别是消费者线程和生成者线程
2、确定共享资源 => Clerk类或产品数量
3、是否涉及线程通信 => 为了协调生产和消费的步调必须进行线程通信
4、是否涉及线程安全 => 两类线程操作共享资源比如产生线程安全问题(用同步方法,同步代码块,Lock解决)
5、对共享资源的操作也需要在资源类中去完成,然后在线程的run方法中直接调用封装好的操作方法
 */
class Clerk{
    
    
    //产品数上限为10
    public static int MAX_PRODUCT = 10;
    //当前第几个产品
    public static int num;

    public synchronized void product(){
    
    
        String name = Thread.currentThread().getName();
        notifyAll();
        if(num <=  MAX_PRODUCT){
    
    
            num++;
            System.out.println("生产者" +name + " 生产第:" +num +"件商品");
        }else{
    
    
            System.out.println("生产过多,停止生产");
            try {
    
    
                this.wait();
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
    }

    public synchronized void consumer(){
    
    
        String name = Thread.currentThread().getName();
        notifyAll();
        if(num > 0){
    
    
            System.out.println("消费者" +name + " 消费第:" +num +"件商品");
            num--;
        }else{
    
    
            try {
    
    
                System.out.println("产品不足,停止消费");
                this.wait();
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
    }
}

class Consumer implements Runnable{
    
    
    private Clerk clerk;

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

    @Override
    public void run() {
    
    

        while (true){
    
    
           clerk.consumer();
        }
    }
}

class Productor implements Runnable{
    
    
    private Clerk clerk;

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

    @Override
    public void run() {
    
    
        String name = Thread.currentThread().getName();
        while (true){
    
    
            clerk.product();
        }
    }
}
/*
1、该模拟中一个生产者对应两个消费者,生产者和消费者必须用同一个clerk来构造否则无法协调工作
2、两个消费者线程必须用同一个customer构造,否则会出现线程安全问题,如果用不同的customer构造
需要将同步方法声明为静态同步方法
3、一个生产者对应多个消费者就会经常出现消费大于生成的场景,反之就会出现生成大于消费的场景,我们还
可以使用sleep来阻碍生产或消费
 */
public class Test {
    
    
    public static void main(String[] args) {
    
    
        Clerk clerk = new Clerk();
        Consumer consumer = new Consumer(clerk);
        Thread customer = new Thread(new Consumer(clerk));
        customer.setName("customer");
        Thread customer2 = new Thread(new Consumer(clerk));
        customer2.setName("customer2");
        Thread productor = new Thread(new Productor(clerk));
        customer.setName("productor");
        customer.start();
//        customer2.start();
        productor.start();
    }
}

结果是随机的,无限循环的。大体如上分析
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/wwwwwww31311/article/details/113481765