Чтобы усилить комментарий выше nos:
volatile - подсказка компилятору, что переменная может быть изменена извне, и поэтому значение не должно быть помещено в регистр в качестве оптимизации; каждый раз, когда на переменную ссылаются, ее значение должно быть получено из ее местоположения в памяти.
Это замечательно, насколько это возможно, но это не делает ничего, чтобы предотвратить условия гонки с участием переменной, где t1 и t2 одновременно обновляют переменную, и вы не получаете конечного значения, которое ожидаете. В этом случае вы используете блокировку, чтобы гарантировать, что у вас есть эксклюзивный доступ к общей переменной, прежде чем вы ее измените.
Замки не без их ловушек, так как вы можете попасть в тупиковую ситуацию или иметь довольно низкую производительность, если не будете осторожны.