No, the synchronized block in thread B does not ensure that it will read the actual current value of counter
. You would need synchronized blocks in both threads to do that. From a practical perspective, your code ensures that the processor running thread B invalidates its cache and reads the value of counter
from main memory, but it does not ensure that the processor running thread A flushes its current value to main memory, so the value in main memory may be stale.
Since using a volatile variable is cheaper than synchronized blocks in both threads, making counter
volatile is likely the correct solution. This is what volatile variables are for.
Edit: if thread A is going to complete before thread B reads the final value, you could enclose the entire execution of thread A in a single synchronized block or have thread B join thread A before reading the counter, ensuring that thread A completes before the counter is read. That would result in one cache flush at the end of Thread A's execution, which would have negligible impact on performance.