Шаблон Producer Consumer. Не всегда проходит тест

162
04 декабря 2018, 13:10

Вот сам код:

import net.jcip.annotations.GuardedBy;
import net.jcip.annotations.ThreadSafe;
import java.util.LinkedList;
import java.util.Queue;
/**
 * Класс состоит их двух методов:
 * Первый добавляет элементы в коллекцию если очередь не полна.
 * Второй извлекает элементы из коллекции если очередь не полна.
 */
@ThreadSafe
public class SimpleBlockingQueue<E> {
    @GuardedBy("this")
    private Queue<E> queue = new LinkedList<>();
    @GuardedBy("this")
    private E size;
    public SimpleBlockingQueue(E size) {
        this.size = size;
    }
    public synchronized void offer(E value) {
        if (queue.size() > (int) size) {
            try {
                wait();
            } catch (InterruptedException e) {
                System.out.println("Исключения типа InterruptedException перехвачено");
            }
        } else {
            queue.offer(value);
            notify();
        }
    }
    public synchronized E poll() {
        E result = null;
        if (queue.isEmpty()) {
            try {
                wait();
            } catch (InterruptedException e) {
                System.out.println("Исключения типа InterruptedException перехвачено");
            }
        } else {
            result = queue.poll();
            notify();
        }
        return result;
    }
    public synchronized int getSizeQueue() {
        return queue.size();
    }
}

Вот код теста:

import org.junit.Before;
import org.junit.Test;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.*;
public class SimpleBlockingQueueTest {
    SimpleBlockingQueue<Integer> blocking = new SimpleBlockingQueue<>(7);
    private Thread producer;
    private Thread consumer;
    @Before
    public void when() {
        producer = new Thread() {
            @Override
            public void run() {
                int i = 0;
                while (i < 6) {
                    blocking.offer(i);
                    i++;
                }
            }
        };
        consumer = new Thread() {
            @Override
            public void run() {
                int i = 0;
                while (i < 6) {
                    assertThat(blocking.getSizeQueue(), is(6 - i));
                    assertThat(blocking.poll(), is(i));
                    assertThat(blocking.getSizeQueue(), is(6 - 1 - i));
                    i++;
                }
            }
        };
    }
    @Test
    public void start() throws InterruptedException {
        producer.start();
        consumer.start();
        producer.join();
        consumer.join();
    }
}

Иногда проходит тест, а иногда бывают ошибки:

Answer 1

Судя по всему тест проверяет только, что элементы были добавлены в нужном порядке.

Проблема связана с тем, что нет гарантии, что producer выполнится раньше consumer. В запусках, которые не проходят, consumer выполняется первым и не обнаруживает элементов в очереди.

Чтобы исправить можете сначала дождаться пока producer завершит работу:

producer.start();
producer.join();
//и после запускаем consumer
consumer.start();
consumer.join();

Насколько это решение допустимо зависит от поставленной перед тестом задачи. Если просто нужно протестировать порядок элементов в очереди, то этот вариант подойдет, но в этом случае можно обойтись и без потоков. Если же нужно протестировать параллельную работу, то этот вариант не подойдет, нужно будет либо настраивать синхронизацию потоков, либо строить логику получения значения чтобы consumer дожидался следующего значения, перед тем как его сверять.

READ ALSO
Пофиксить ошибку Last packet sent to the server was 28 ms ago

Пофиксить ошибку Last packet sent to the server was 28 ms ago

Имеется игровой сервер, который использует hibernate для работы с базой данных, спустя n-времени, сервер просто выдает такую ошибку:

175
Не работает гамбургер (при нажатии меню не открывается)

Не работает гамбургер (при нажатии меню не открывается)

Не открывается почему то меню при нажатии на гамбургерБраузер пишет: "ReferenceError: toggleMenu is not defined"

224
Привязка кнопки веб-элемента к кнопке на клавиатуре

Привязка кнопки веб-элемента к кнопке на клавиатуре

Подскажите, как привязать событие нажатия на кнопку button к кнопке на клавиатуре?

182
Неадекватная работа слайдера с табами

Неадекватная работа слайдера с табами

В общем сделал слайдер, нормально работает(slick slider), сунул всё это дело в табы и при переключении по ним он как бы есть(но его как бы нет)Что...

220