Проверьте тест.
Возьмите копию метода, который должен быть потокобезопасным, и сделайте копию небезопасной. Напишите unit-test, который запускает до дюжины потоков с возможностью выполнения:
1) Имеет общий CountDownLatch.
2) Ожидает, что CountDownLatch достигнет нуля.
3) Вызывает небезопасный метод.
С CountDownLatch вы можете инициировать все потоки, чтобы вызвать небезопасный метод нить более или менее в одно и то же время (все потоки готовы перейти от одной и той же точки в runnable, когда CountDownLatch достигает нуля, но в конечном итоге это вплоть до вашей операционной системы (и оборудования), чтобы решить, что будет выполняться, когда). Оцените результаты: теперь вы должны увидеть расхождение (например, 11 записей, вставленных вместо ожидаемых 12).
Повторите тест или поместите тест в цикл (и замените CountDownLatch на CyclicBarrier, еще один параллельный инструмент, который пригодится для такого рода тестов). В любом случае убедитесь, что ваш тест всегда показывает нежелательный результат (например, никогда не предполагайте, что потоки запускаются в одно и то же время, синхронизируйте их с такими инструментами, как CountDownLatch, чтобы вы точно знали, где существуют потоки).
Заменить вызов метода, небезопасного с потоком, с вызовом метода поточной защиты в модульном тесте. Теперь вы должны увидеть желаемые и ожидаемые результаты без расхождений.
Здесь я не особо подробно остановился, но в вопросе также не так много деталей. В любом случае общая идея состоит в том, чтобы сначала настроить ситуацию, когда она должна идти не так, и использовать автоматическую грубую силу (многие потоки, вызывающие метод много раз в цикле) в сочетании с умным использованием параллельных инструментов, таких как CountDownLatch, чтобы показать тест всегда будет вызывать определенные проблемы. «Умное использование параллельных инструментов» займет некоторое время, понимание и практика (например, мне потребовалось некоторое время, чтобы понять, что после вызова «thread.start()» поток, возможно, еще не начался и что можно использовать CountDownLatch чтобы убедиться, что нить там, где я хочу, чтобы она была).
Отказ от ответственности: эти «проверенные» тесты не поймут все проблемы параллелизма (вы проверяете только то, что, по вашему мнению, может потерпеть неудачу, а также есть другие проблемы, например, сломанные Double checked locking), но они будут затвердеть ваш код и принести вероятный проблемы параллелизма на поверхность.
Почему вы не используете стандартные транзакции? – chrylis
@chrylis Можете ли вы подробно рассказать? Вы говорите о спящих транзакциях? – Siddhartha