猿问

对单个静态整数索引进行多次读写会导致索引越界

我试图学习多线程,并尝试使用等待和通知的简单生产者/消费者模式。当我将模式拆分为两个消耗和一个产生时,我得到一个 ArrayIndexOutOfBounds 异常,该异常尚不清楚。该问题并不总是发生,有时会发生。我使用的是 I3 处理器。


我尝试添加一个 if 块来检查计数变量是否低于或高于声明的大小,但问题仍然存在。



    private static Object key = new Object();

    private static int[] buffer;

    private volatile static Integer count;


    static class Consumer {


        void consume() {

            synchronized (key) {

                if (isEmpty()) {

                    try {

                        key.wait();

                    } catch (InterruptedException e) {

                        e.printStackTrace();

                    }

                }

                buffer[--count] = 0;

                key.notify();

            }

        }


        public boolean isEmpty() {

            return count == 0;

        }

    }


    static class Producer {


        void produce() {

            synchronized (key) {

                if (isFull()) {

                    try {

                        key.wait();

                    } catch (InterruptedException e) {

                        e.printStackTrace();

                    }

                }

                buffer[count++] = 1;

                key.notify();

            }

        }


        public boolean isFull() {

            return count == buffer.length;


        }

    }

    public static void main(String[] args) throws InterruptedException {

        buffer = new int[10];

        count = 0;

        Producer producer = new Producer();

        Consumer consumer = new Consumer();

        Runnable produce = () -> {

            for (int i = 0; i < 1500; i++)

                producer.produce();

            System.out.println("Done producing");

        };

        Runnable consume = () -> {

            for (int i = 0; i < 1300; i++)

                consumer.consume();

            System.out.println("Done consuming");

        };


        };


富国沪深
浏览 110回答 2
2回答

拉莫斯之舞

问题是:对于“满”和“空”状态,您只有一个共享的等待条件您正在运行两个消费者线程(“consumerWorker”和“delayedConsumer”)和一个生产者线程(“ ProducerWorker”)你没有像你应该的那样重新检查 while 循环中的条件可能发生的事情是:两个消费者线程都看到缓冲区为空生产者线程将一项放入缓冲区并发出通知。单个消费者线程唤醒并处理一项。缓冲区现在是空的。然后它会发出通知。第二个消费者线程醒来(而不是像您预期的那样的生产者),不检查缓冲区是否为空,并尝试访问索引 -1 处的缓冲区。您从通话中醒来后需要重新检查情况wait。将 更改if为while. 以下是如何为消费者做到这一点;您需要为制作人做同样的事情。    void consume() {        synchronized (key) {            while (isEmpty()) {                try {                    key.wait();                } catch (InterruptedException e) {                    e.printStackTrace();                }            }            buffer[--count] = 0;            key.notify();        }    }这样消费者就不会被来自notify其他消费者线程的 所迷惑。

函数式编程

你的缓冲区长度为 10buffer&nbsp;=&nbsp;new&nbsp;int[10];因此,每当您的计数变量超过数组容量(即 10)时,就会很明显&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;volatile&nbsp;static&nbsp;Integer&nbsp;count;你会得到ArrayIndexOutOfBoundsException您生产更多,消耗更少,消耗更少,并且生产/消费的执行不是顺序的,它更像是循环。
随时随地看视频慕课网APP

相关分类

Java
我要回答