Я хотел бы добавить некоторые подробности об ответе на этот вопрос.
Во-первых, ОП спрашивает:
Как я могу сделать эти операции безопасными для потока?
Прежде чем ответить на этот вопрос, нам необходимо достичь согласованности относительно того, что поточно-ориентировано . Мне больше всего нравится определение из «Параллелизма Java на практике», и оно
Класс является потокобезопасным, если он ведет себя правильно при обращении
из нескольких потоков, независимо от планирования или
чередование выполнения этих потоков во время выполнения
окружающей среды, и без дополнительной синхронизации или другого
согласование со стороны вызывающего кода.
Если вы согласны с определением, это означает, что мы достигли согласованности до дальнейшего обсуждения. Давайте вернемся к операциям, которые вы имели в виду, это a++
и b++
, после приращения вы поместите их в HashTable
.
Для операции a++
на самом деле это не единственная операция. Он подчиняется модели read modify write . Как видите, на самом деле он содержит три отдельных шага. Прочитайте значение, добавьте его и сохраните обратно. Если у вас есть два потока, прочитайте переменную a
со значением 1
одновременно, после внесения изменений и сохранения обратных операций. Значение будет 2
, но на самом деле оно должно быть 3
. Чтобы избежать этой ситуации, как и другие, вы можете использовать AtomicInteger
вместо int
напрямую. AtomicInteger
гарантирует, что некоторые операции, такие как инкремент, будут выполняться атомарно. Это означает, что операции read edit write не могут быть разделены и будут выполняться как один отдельный шаг.
После этого OP хочет сохранить значение в HashTable. HashTable - это потокобезопасный контейнер, никакой другой синхронизации не требуется.
Надеюсь, что это разъяснение может помочь кому-то по-другому. Спасибо.