多线程-生产者消费者模式

多线程-生产者消费者模式

一个生产者一个消费者(这里以厨师和顾客为例,代码如下)

class Resourse {//建立一个资源类,生产者消费者都对同一个资源进行操作
    private String name;//资源名字
    private int count = 1;//资源编号
    String msg ;
    private boolean haveFood = false;//定义一个状态,有食物或者没有食物,用于判断是否生产和是否消费。

    public Resourse(String name) {
        super();
        this.name = name;
    }

    public synchronized void cook() {//同步函数,同步锁为this
    if (haveFood == true)//判断是否有食物
            try {
                wait();//如果有食物生产线程进入阻塞状态。
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        System.out.println(Thread.currentThread().getName()+"....生产者生产...." + name+count);
        msg = name+count;
        count++;
        haveFood = true;
        notify();//生产完成之后唤醒消费者线程前来消费。
    }
    //消费者动作同上
    public synchronized void buy() {
        if(haveFood == false)
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        System.out.println(Thread.currentThread().getName()+"....消费者消费..............." + msg);
        haveFood = false;
        notify();
    }

}
//建立生产者消费者类,分别实现Runnable接口,run方法内确定线程任务,构造方法用于确定线程操作资源。
class Producter implements Runnable {
    Resourse r ;
    public Producter(Resourse r)
    {
        this.r = r;
    }
    public void run() {
        while(true)
            r.cook();
    }
}
class Consumer implements Runnable
{
    Resourse r ;
    public Consumer(Resourse r)
    {
        this.r = r;
    }
    public void run()
    {
        while(true)
            r.buy();
    }
}

public class ProducterConsumerDemo {
    public static void main(String[] args) {
        Resourse r = new Resourse("汉堡");
        Producter pro = new Producter(r);
        Consumer con = new Consumer(r);
        Thread t0 = new Thread(pro);
        Thread t1 = new Thread(con);
        t0.start();
        t1.start();
    }
}

到这里一生产者一消费者代码完成,但是这代码不能用于多生产多消费模式。会产生以下错误。

-生产者生产了两次消费者却只消费了一次:

Thread-0....生产者生产....汉堡48101
Thread-1....生产者生产....汉堡48102
Thread-3....消费者消费...............汉堡48102
//分析:(4个线程)
    public synchronized void cook() {//t0,t1
    if (haveFood == true)//判断是否有食物
            try {
                wait();//如果有食物生产线程进入阻塞状态。
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        System.out.println(Thread.currentThread().getName()+"....生产者生产...." + name+count);
        msg = name+count;
        count++;
        haveFood = true;
        notify();//生产完成之后唤醒消费者线程前来消费。
    }
    public synchronized void buy() {//t2,t3
        if(haveFood == false)
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        System.out.println(Thread.currentThread().getName()+"....消费者消费..............." + msg);
        haveFood = false;
        notify();
    }
模拟步骤:
  1. 设t0抢到执行权,t0执行完成,生产汉堡1,将haveFood改为true,并唤醒一个线程(此处认为线程池中暂时没有线程),因为run()中的while(true)循环,t0继续执行,判断haveFood为true,t0进入阻塞状态,释放线程锁this。
  2. 设t1抢到执行权,t1判断haveFood为true,则t1进入阻塞状态,释放线程锁this。
  3. 设t2抢到执行权,t2执行完毕,消费汉堡1,将haveFood改为false,并唤醒一个线程(t0或者t1),然后t2回去判断haveFood为false,t2进入阻塞状态,释放线程锁。
  4. 设t0抢到执行权,此时不会判断haveFood,直接生产汉堡2,唤醒一个线程(假设唤醒t1)然后将haveFood改为true,进入阻塞。
  5. 设t1抢到执行权,此时也不会再回去判断haveFood 直接生产汉堡3,此时几经出现问题,汉堡2不会再被消费者消费。
解决方法:
  • 问题的关键在于t0和t1从阻塞状态恢复成可执行状态,抢到执行权之后不会再判断haveFood,所以把if(haveFood)改为while(haveFood)让线程每次醒来都要回去判断状态。
  • 但是如此一来又会产生新的问题,如果t0执行完成,将haveFood改为true,唤醒的是本方,也就是同为生产者线程的t1,则t1执行,判断haveFood为true,t1也进入阻塞状态,t2,t3也做同样操作,则线程全部进入阻塞,发生死锁现象。
  • 于是,我们要把notify()改为notifyAll(),这样就确保了唤醒了对方的线程。

多生产多消费模式(代码如下)

class Resourse {
    private String name;
    private int count = 1;
    String msg ;
    private boolean haveFood = false;

    public Resourse(String name) {
        super();
        this.name = name;
    }

    public synchronized void cook() {

        while(haveFood ==true)
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        System.out.println(Thread.currentThread().getName()+"....生产者生产...." + name+count);
        msg = name+count;
        count++;
        haveFood = true;

        notifyAll();
    }

    public synchronized void buy() {

        while(haveFood == false)
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        System.out.println(Thread.currentThread().getName()+"....消费者消费..............." + msg);
        haveFood = false;

        notifyAll();
    }

}

class Producter implements Runnable {
    Resourse r ;
    public Producter(Resourse r)
    {
        this.r = r;
    }
    public void run() {
        while(true)
            r.cook();
    }
}
class Consumer implements Runnable
{
    Resourse r ;
    public Consumer(Resourse r)
    {
        this.r = r;
    }
    public void run()
    {
        while(true)
            r.buy();
    }
}

public class ProducterConsumerDemo {
    public static void main(String[] args) {
        Resourse r = new Resourse("汉堡");
        Producter pro = new Producter(r);
        Consumer con = new Consumer(r);
        Thread t0 = new Thread(pro);
        Thread t1 = new Thread(pro);
        Thread t2 = new Thread(con);
        Thread t3 = new Thread(con);
        t0.start();
        t1.start();
        t2.start();
        t3.start();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值