首页 新闻 会员 周边 捐助

生产者与消费者问题,一个生产者多个消费者,为什么只有一个消费者参与消费?

0
悬赏园豆:50 [已解决问题] 解决于 2020-11-21 18:43

预计输出,
一个生产者生产 --------------------------------------------------
消费者1 消费-----------------------------------------------------

生产者生产 -------------------------------------------------------
消费者2消费--------------------------------------------------------

主方法 创建生产者消费者

public class ProAndCon {
    public static void main(String[] args) {
        List list =new ArrayList();

        ProThread proThread1=new ProThread(list);
        ProThread proThread2=new ProThread(list);
        ConThread conThread1=new ConThread(list);
        ConThread conThread2=new ConThread(list);
        proThread1.setName("生产1");

        conThread1.setName("消费1");
        conThread2.setName("消费2");

        proThread1.start();
        conThread1.start();
        conThread2.start();
    }
}
//生产线程
class ProThread extends Thread{
    private  List list;
    ProThread(List list) {
        this.list = list;
    }

    @Override
    public void run() {
        synchronized (list) {
            while (true) {
                if (list.size() > 0) {
                    try {
                        list.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                Object object = new Object();
                list.add(object);
                System.out.println(Thread.currentThread().getName() + "生产 list" + object);
                list.notifyAll();
            }
        }
    }
}
//消费线程

class  ConThread extends  Thread{
    private  List list;
    public ConThread(List list) {
        this.list=list;
    }
    @Override
    public void run() {

        while (true){
            synchronized (list){
            if (list.size()==0){
                try {
                    list.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
           Object object= list.remove(0);
            System.out.println(Thread.currentThread().getName()+"消费 list"+object);
            list.notifyAll();
        }
    }
    }
}

出现问题,一直就是单个生产者,单个线程消费者,多次运行,变换消费者,单还是一直一个消费者

酒浊的主页 酒浊 | 初学一级 | 园豆:78
提问于:2020-11-18 14:49
< >
分享
最佳答案
0

因为wait和notifyAll的机制,list.wait只有持有list锁的对象才能调用,list.notifyAll只会唤醒调用由list锁调用wait进入等待的线程。
所以你的程序是这样运行的(这里假设生产者先拿到锁,其他几种情况的问题都和下面一样):
1.消费者1和消费者2和生产者1在第一次时竞争锁,假设生产者先拿到锁,处理后,唤醒所有list锁调用的等待线程,然后再因list.size>0进入等待状态,释放锁。
2.这时俩个消费者互相竞争,假设消费者1拿到锁,处理后,唤醒所有list锁调用的等待线程(这里是生产者),注意这时消费者1还没有释放锁,直到循环到判断语句,因list.size=0进入等待状态,才释放锁。
3.生产者被唤醒,拿到锁,继续处理,处理后,唤醒所有list锁调用的等待线程(这里只会唤醒消费者1,因为消费者2根本没有机会拿到锁去调用list.wait),然后再因list.size>0进入等待状态,释放锁。
可以发现只有第一波消费者之间的竞争是平衡,当第一波过后,抢不到锁的消费者就再也拿不到锁了,因为notifyAll只会唤醒调用由list锁调用wait进入等待的线程,而wait方法只有获取到锁是才能去调用。(语文不好,有点绕,希望看得懂)

收获园豆:50
小高飞 | 初学一级 |园豆:84 | 2020-11-21 17:33

我觉在第一波之后 抢不到锁得消费者就再也拿不到锁了,这个说的太绝对,当我在消费者锁代码块外,无限循环体内,让其线程睡眠100毫秒时,出现两个不同的消费者,交替消费。但是这个list.notifyAll只会唤醒由list锁调用wait 进入等待得线程这点,学到了。谢谢老哥了。

酒浊 | 园豆:78 (初学一级) | 2020-11-21 18:40

@博lbobo: 听你这么说我发现我还真说错了,汗(lll¬ω¬),我又去把你代码debug一下:
应该是这样的,当执行完synchronized代码块里的代码后,list锁已经是释放了,但是cpu的使用权并没有释放,直到调用了wait方法,所以另一个消费者一直没有执行是因为当获取到cpu使用权时,list已经为0了,而list不为0时又因为锁被notifyAll唤醒的消费者拿去了(因为该消费者已经执行到synchronized代码块内了)。而你填加了sleep方法后,就会去释放cpu的使用权,这时另一个消费者就有机会在list不为0时去抢cpu的使用权并去增夺锁了(因为两个消费者都在synchronized代码块门口)。你可以添加sleep的代码和添加前的代码分别debug一下,断点打在生产者的wait方法,和消费者的if语句、notifyAll和sleep,就可以看出了。
这里要说一下,sleep只会释放cpu的使用权,而wait不仅会释放cpu的使用权还会释放锁。

小高飞 | 园豆:84 (初学一级) | 2020-11-21 19:55
其他回答(3)
0

建议代码好好格式化一下,看着太乱了。这个编辑器是支持格式化代码的

会长 | 园豆:12463 (专家六级) | 2020-11-19 09:34

ok

支持(0) 反对(0) 酒浊 | 园豆:78 (初学一级) | 2020-11-19 09:42
0
czd890 | 园豆:14488 (专家六级) | 2020-11-19 11:10
0

你这个代码生产者生产一个产品后就会阻塞自己直到一个消费者消费了产品,消费者消费一个产品就会阻塞自己直到生产者生产了一个产品。所以一直都是生产者生产一个,消费者消费一个。
可以改为产品数量小于一个值生产者再生产,产品数量不为0消费者再消费

不入凡尘 | 园豆:202 (菜鸟二级) | 2020-11-20 10:04

不是应该是,生产者生产一个产品后,唤醒所有等待的线程,两个线程都在While true上面一直执行,两个都应该有机会抢到线程呀,拿到对象锁呀,

支持(0) 反对(0) 酒浊 | 园豆:78 (初学一级) | 2020-11-20 15:01

另外您说的那个我把生产者,生产10个,唤醒消费者,让消费者消费,结果还是一个消费者消费10次,另一个消费者不动,

支持(0) 反对(0) 酒浊 | 园豆:78 (初学一级) | 2020-11-20 15:02
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册