Наличие только 1-х потоковой блокировки ничего не дает. Цель блокировки - заблокировать другие потоки, но она не работает, если никто больше не проверяет блокировку!
Теперь вам не нужно беспокоиться о повреждении памяти 32-битным int, потому что запись является атомарной - но это не обязательно означает, что вы можете выйти без блокировки.
В вашем примере можно получить сомнительную семантику:
example = 10
Thread A:
Add(10)
read example (10)
Thread B:
Read()
read example (10)
Thread A:
write example (10 + 10)
, что означает, что ThreadB начал читать значение примера после того, как поток A начал свое обновление - но прочитал предварительно обновленное значение. Полагаю, это проблема или нет, зависит от того, что должен делать этот код.
Так как это пример кода, может быть трудно увидеть проблему там. Но представьте себе каноническую функцию счетчика:
class Counter {
static int nextValue = 0;
static IEnumerable<int> GetValues(int count) {
var r = Enumerable.Range(nextValue, count);
nextValue += count;
return r;
}
}
Тогда следующий сценарий:
nextValue = 9;
Thread A:
GetValues(10)
r = Enumerable.Range(9, 10)
Thread B:
GetValues(5)
r = Enumerable.Range(9, 5)
nextValue += 5 (now equals 14)
Thread A:
nextValue += 10 (now equals 24)
Значение nextValue увеличивается должным образом, но возвращаемые диапазоны будут перекрываться. Значения 19 - 24 никогда не возвращались. Это можно исправить, заблокировав присваивание var r и nextValue, чтобы предотвратить одновременное выполнение любого другого потока.