首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java生产者消费者模型总是死锁

Java生产者消费者模型总是死锁
EN

Stack Overflow用户
提问于 2015-03-01 15:41:07
回答 1查看 106关注 0票数 0

因此,我有了这个评估,为家庭作业制作了一个生产者消费者模型,我完成了一个非常粗糙的版本(但我用我目前的java技能所能做的最好的)。

它看起来很有效,但是它遇到了Wiki链接描述的死锁问题,这就是,基本上由于某种原因,所有线程最终都会睡着,无法唤醒彼此,进入永恒的睡眠周期。

我不太清楚代码中到底是什么导致了这种情况,因为我本以为我写它的方式不会发生这种情况,但我仍然不完全理解线程是如何工作的。

这是我的密码:

代码语言:javascript
复制
package boundedbuffer;

import java.util.LinkedList;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.Queue;


public class BoundedBuffer {


    public static int CapacityCheck = 0;


    public static void main(String[] args){


        MessageQueue queue = new MessageQueue(3); // <-- max capacity of queue is given here as 3

        Thread t1 = new Thread(new Producer(queue));
        Thread t2 = new Thread(new Producer(queue));
        Thread t3 = new Thread(new Producer(queue));  
        Thread t4 = new Thread(new Consumer(queue));
        Thread t5 = new Thread(new Consumer(queue));
        Thread t6 = new Thread(new Consumer(queue));
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
        t6.start();

    }
}

public class Producer implements Runnable{

    private MessageQueue queue;

    private static String msgs[] = {
            "some test message",
            "long message",
            "short message",
            "yet another message"
        };

    public Producer(MessageQueue queue){
        this.queue = queue;
    }

    @Override
    public synchronized void run() {
        while(true){
            Random rand = new Random();
            int wait = rand.nextInt(3000);
            int index = rand.nextInt(4);
            try {
                Thread.sleep(wait);
            } catch (InterruptedException ex) {
                Logger.getLogger(Producer.class.getName()).log(Level.SEVERE,
                null, ex);
            }         
            if(BoundedBuffer.CapacityCheck < queue.capacity){ 
                System.out.println("Puts into buffer: " + msgs[index]);
                queue.put(msgs[index]);
                BoundedBuffer.CapacityCheck++;
                notifyAll();
            }else{
                try {
                    wait();
                } catch (InterruptedException ex) {
                    Logger.getLogger(Producer.class.getName()).log(Level.SEVERE,                        null, ex);            
                }
            }
        }

    }

}

public class Consumer implements Runnable{

    private MessageQueue queue;

    public Consumer(MessageQueue queue){
        this.queue = queue;
    }

    @Override
    public synchronized void run() {
        while(true){
            Random rand = new Random();
            int wait = rand.nextInt(3000);
            try {
                Thread.sleep(wait); 
            } catch (InterruptedException ex) {
                Logger.getLogger(Consumer.class.getName()).log(Level.SEVERE, null, ex);
            }
            String msg = queue.get();
            if(msg == null){
                try {
                    wait();
                } catch (InterruptedException ex) {
                    Logger.getLogger(Consumer.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            queue.get();
            BoundedBuffer.CapacityCheck--;
            System.out.println("Takes out of buffer: " + msg);
            notifyAll();        
        }
    }


}


public class MessageQueue  {

    public final int capacity;
    private final Queue<String> messages = new LinkedList<>();


    public MessageQueue(int capacity) {
        this.capacity = capacity;
    }

    public void put(String msg){
        this.messages.add(msg);
    }

    public String get(){ 
        if(messages.isEmpty()){ 
            return null;
        }else{
            String msg = messages.element();
            messages.remove();
            return msg;
        }
    }
}

另一个小问题,但有趣的是,我从来没有或可能只有一次看到的情况下,“拿出一个项目”发生了不止一次在彼此之间。每次放入项目都会发生一次、两次或最多三次(我在本例中设置了缓冲区大小为3,因此不能发生4次),但取出一个项目可能只发生一次,然后它总是返回一个,取出一个,返回一个。我从来没有见过在三个项目被放入之后:拿出一个,再取出一个,例如。

这可能是一个问题或一个错误。Idk。

我还认为在运行方法上使用同步的感觉有点不太好,但是如果我去掉它,就会得到一个IllegalMonitorState异常。

我使用多个生产者和多个消费者,因为这是我的老师要求我们这样做的。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-03-01 15:48:59

所有线程失速都是因为您在传递给线程的不同生产者和使用者上获得互斥对象。

您在run方法上同步,这意味着在调用wait方法时获得不同对象上的互斥,并在假定有人通知线程返回时进入阻塞状态。即使其他线程通知,它们也会通知这个实例(单个生产者或消费者)实例,而不是生产者和使用者之间的共享实例。

共享公共实例,就像您正在执行MessageQueue一样,并在队列上而不是在run方法上同步。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28795452

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档