Java: Is volatile / final required for reference to synchronized object?

后端 未结 5 802
陌清茗
陌清茗 2021-01-04 02:52

This seems a pretty basic issue, but I cannot find a clear confirmation.

Let\'s say I have a class properly synchronized in itself:

public class Sync         


        
5条回答
  •  刺人心
    刺人心 (楼主)
    2021-01-04 03:30

    Yes you are right. It is necessary that you make access to the variable also thread-safe. You can do that either by making it final or volatile, or you ensure that all threads access that variable again inside a synchronous block. If you wouldn't do that, it might be that one thread 'sees' already the new value of the variable, but the other thread might still 'see' null, for example.

    So regarding your example, you could sometimes get a NullPointerException when a thread accesses the mySharedObject variable. But this might only happen on multi-core machines with multiple caches.

    Java Memory Model

    The main point here is the Java Memory Model. It states a thread is only guaranteed to see a memory update of another thread if that update happens before the read of that state in the so-called happens-before relation. The happens-before relation can be enforced by using final, volatile, or synchronized. If you do not use any of these constructs a variable assignment by one thread is never guaranteed to be visible by any other thread.

    You can think of threads to conceptually have local caches and as long as you do not enforce that caches of multiple threads are synchronized, a thread just reads and writes to its local cache. This might lead to the situation where two threads see completely different values when reading from the same field.

    Note that there are some additional ways to enforce visibility of memory changes, for example, using static initializers. In addition, a newly created thread always sees the current memory of its parent thread, without further synchronization. So your example might even work without any synchronization, because the creation of your threads are somehow enforced to happen after the field has been initialized. However relying on such a subtle fact is very risky and can easily break if you later refactor your code without having that detail in mind. Further details about the happens-before relation are described (but hard to understand) in the Java Language Specification.

提交回复
热议问题