生产者消费者模式的实现和线程间的通信

生产者消费者模式的实现

生产者消费者模式原理:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据。
产生的问题:数据错乱,如:生产者生产旺仔-牛奶,和娃哈哈-矿泉水。用一个商品类表示生产者和消费者共享的数据,类中有两属性商品的品牌(brand)和商品的名称(name)。假设生产者生产一种产品,当被消费了再继续生产。当生产者生产产品时,即向商品类中写入数据,如(brand=“旺仔”;name=“牛奶”);然后消费者就行消费,即读取数据(brand=“旺仔”;name=“牛奶”);当生产者再向商品类中写入数据时(娃哈哈-矿泉水),如只赋值了brand="娃哈哈"时,由于线程并发的原因,可能此时生产者赋值被阻塞,然后消费者类就行读取数据,此时读出来的是(brand=“娃哈哈”;name=“牛奶”),所以数据就错乱了。还可能出现重复生产和重复取走。

解决方法:线程间的通信,即当生产执行完之后才进行消费,当消费执行完再进行生产,这样彼此之间不进行干扰。

线程间的通信

线程间通信的方法(以下是Object类中的方法)
wait():调用了wait()方法的线程进入等待池进行等待,等待池中的线程不去竞争对象锁,直到其他线程唤醒才能有资格获取资源继续执行。
notify():随机唤醒一个在该对象上等待的线程。
notifyAll():唤醒所有在该对象上等待的线程。

Thread.sleep()和Object.wait()的区别
Thread.sleep()和Object.wait()都会暂停当前的线程,这两张方式暂停的线程,都表示它暂时不再需要CPU的执行时间。操作系统会将执行时间分配给其它线程。区别是调用wait()后,需要别的线程执行notify()/notifyAll()才能够重新获得CPU执行时间。

生产者消费者模式的代码实现
商品类:

public class Goods {
    private String brand;
    private String name;
    public boolean flag;//判断是否有商品
    public Goods(String brand, String name) {
        this.brand = brand;
        this.name = name;
    }
    public Goods(){}

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

//    设置brand和name
    public synchronized void set(String brand,String name){
        if(flag){
            try {
                super.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        setBrand(brand);
        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        setName(name);
        System.out.println("生产者生产了:"+brand+"-"+name);
        flag = true;
        super.notify();
    }

//    获取值
    public synchronized void get(){
        if(!flag){
            try {
                super.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("消费者获取了:"+brand+"-"+name);
        flag=false;
        super.notify();
    }
}

生产者类:

public class Producter extends Thread{
    Goods good = new Goods();
    public Producter(Goods good){
        this.good = good;
    }
    @Override
    public void run() {
        for(int i=0;i<10;i++){
            if(i%2==0){
                good.set("旺仔","牛奶");
            }else{
                good.set("娃哈哈","矿泉水");
            }
        }
    }
}

消费者类:

public class Customer extends Thread{
    Goods good = new Goods();
    public Customer(Goods good){
        this.good = good;
    }
    @Override
    public void run() {
        for (int i=0;i<10;i++){
            good.get();
        }
    }
}

测试类:

public class Test {
    public static void main(String[] args) {
        Goods goods = new Goods();
        Producter pr = new Producter(goods);
        Customer ct = new Customer(goods);
        pr.start();
        ct.start();
    }
}

代码解读:生产者对商品类中的属性赋值,当商品类中有产品(即已赋值),标识flag=true;如果flag=true,生产者的赋值代码块调用wait()进行等待,而消费者进行取值(即取出商品了),flag=false,同时调用方法notifyAll()进行唤醒生产者的生产行为(进行赋值)。如果flag=false,生产者的赋值行为可以执行,消费者的取值需要进行等待,要等生产者赋值结束了才被唤醒。

©️2020 CSDN 皮肤主题: 游动-白 设计师:上身试试 返回首页