Как проверить блокировку чтения и записи с помощью JUnit?

#java #multithreading #junit #thread-safety

#java #многопоточность #junit #потокобезопасность

Вопрос:

У меня есть два метода: один для чтения и один для записи. Они оба обращаются к одной и той же коллекции и используются в нескольких потоках. Например, три потока для записи и восемь — для чтения. Мне нужно проверить потокобезопасность моей коллекции. Метод записи имеет приоритет.

 public static void insertEntity(Entity entity) {
        try {
            readWriteLock.writeLock().lock();

            Session session = sf.openSession();
            session.beginTransaction();

            GenericDAO.insertEntity(session, entity);

            session.getTransaction().commit();
            session.close();
        } finally {
            readWriteLock.writeLock().unlock();
        }
    }


public static Entity getByID(Integer id) {
        try {
            readWriteLock.readLock().lock();

            Session session = sf.openSession();
            Entity entity = GenericDAO.selectByID(session, Entity.class, id);

            session.close();
            return entity;
        } finally {
            readWriteLock.readLock().unlock();
        }

    }
  

Комментарии:

1. Я не уверен, понимаю ли я вопрос. Если блокировки применяются правильно, нет необходимости проверять саму потокобезопасность. Давайте сделаем некоторые предположения о readWriteLock : (а) он используется только этими двумя методами (или также корректен в других местах) и (б) он не используется ни в одном из методов, вызываемых между try и finally . В этом случае вы можете положиться на блокировки, которые правильно выполняют работу за вас.

2. @Emmef я тебя понимаю. Но как я могу быть уверен, что я readWriteLock правильно использую, если я не могу протестировать свои методы? Это похоже на использование for i cycle с условием i <1000` для каждого массива, даже если его длина не больше или не равна 1000. Нужно ли мне доверять своим навыкам программиста, чтобы я мог писать код и улучшать его без ошибок? Извините за плохую аналогию

3. Если вы выполняете условия (a) и (b) в моем предыдущем комментарии, я могу сказать вам, что показанное использование блокировок правильное, что также можно проверить в их документации. Помимо этого, тестирование многопоточного кода часто является сложным и ненадежным способом. Это заставляет вас вносить в свой код навязчивые изменения, которые вы не хотели бы вносить в рабочий код. Например, вставка строк с обратным отсчетом и тактические вызовы в разные потоки и в разных потоках. await() countDown() Сложно; не всегда гарантия.

Ответ №1:

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

Кстати: ваш код блокировки неверен. Вы должны unlock() заблокировать только в том случае, если соответствующее lock() выполнено успешно. Шаблон выглядит следующим образом:

 lock.lock();
try {
    // do stuff
} finally {
    lock.unlock();
}