проблема отладки производитель потребительская проблема - PullRequest
0 голосов
/ 11 января 2020

Я пытаюсь понять проблему производителя. Чтобы повторить проблему, я написал следующий код

package com.company;

import java.util.ArrayDeque;
import java.util.Queue;

public class ProducerConsumerProblem {

    private static Queue<Integer> q = new ArrayDeque<>(5);

    public static void main(String args[]) {

        Producer p = new Producer();
        Consumer c = new Consumer();

        Thread t = new Thread( p );
        Thread t1 = new Thread( c );

        t.start();
        t1.start();
    }

    public static class Producer implements Runnable {

        @Override
        public void run() {
            while(true) {
                if (q.size() == 5) {
                    continue;
                }
                System.out.println( "Adding to queue" );
                q.add( 1 );
            }
        }
    }
    public static class Consumer implements Runnable {

        @Override
        public void run() {
            while(true) {
                if (q.size() == 0) {
                    continue;
                }
                System.out.println( "Removing from queue" );
                q.remove();
            }
        }
    }
}

Я ожидал получить что-то вроде concurrent exception, но вместо этого код останавливается, когда очередь пуста или очередь заполнена. Мой вопрос заключается в том, почему код останавливается, когда очередь пуста или заполнена, потому что я поместил и потребителя, и производителя в бесконечное число l oop, даже если они одновременно плохо читают, но в какой-то момент они будут хорошо читать и либо производитель, либо потребитель должен работать. Пожалуйста, помогите мне с ситуацией

1 Ответ

1 голос
/ 11 января 2020

Эти два потока могут видеть разных размеров, поскольку ваш код не является потокобезопасным, а операции добавления и удаления выполняются в разных потоках.

Когда вы делаете q.add( 1 ); в потоке 1 он не обязательно записывает обновленный массив в память (т. е. в ОЗУ), он все еще может находиться в регистрах ЦП, и когда происходит переключение контекста для этих двух потоков, ваши изменения также могут быть пропущены для второго потока и он не видит обновленный размер. Если вы используете синхронизацию, все изменения в блоке синхронизации сохраняются в ОЗУ, когда заканчивается блок сихронизации, так что нежелательное поведение больше не возникает.

Поскольку ArrayDeque не является потокобезопасным, вам потребуется внешняя синхронизация, чтобы сделать ваш поток кода безопасным, или использовать параллельные структуры данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...