#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();
}