Но компиляция выдавала ошибку, говоря, что она должна быть окончательной или эффективно окончательной.
Это потому, что это происходит согласно правилам. Нет, нет, но нет;не имеет значения, действительно ли вы защитились от всех проблем параллелизма или нет - если он не является окончательным, он не скомпилируется.
В вашем упрощенном примере здесь, вероятно, все в порядке. Однако синхронизировать метод не имеет значения, так как локальные переменные всегда будут привязаны к их вызову для каждого потока. Это проблемы с многопоточностью в контексте самого метода, о которых беспокоится компилятор, и это может легко произойти с использованием лямбда-выражений (которые могут быть выполнены некоторое произвольное время в будущем, после того, как состояние неконечной переменной может изменитьсяи, если это так, не совсем понятно, какое состояние следует использовать - начальное состояние или обновленное состояние.)