开发者

Java non-final int(s) visible after construction

开发者 https://www.devze.com 2023-02-17 04:32 出处:网络
I have a java class with a non-final i开发者_StackOverflow社区nt variable that I explicitly initialized in the constructor to 0.All other access to the variable is managed by a ReentrantLock.Do i have

I have a java class with a non-final i开发者_StackOverflow社区nt variable that I explicitly initialized in the constructor to 0. All other access to the variable is managed by a ReentrantLock. Do i have to worry that threads won't see the initial value of 0 because i didn't use the lock in the constructor?


Yes, you have to worry. To avoid problems in this case you need safe publication of the object reference.

From Java Concurrency in Practice:

To publish an object safely, both the reference to the object and the object's state must be made visible to other threads at the same time. A properly constructed object can be safely published by:

  • Initializing an object reference from a static initializer;
  • Storing a reference to it into a volatile field or AtomicReference;
  • Storing a reference to it into a final field of a properly constructed object; or
  • Storing a reference to it into a field that is properly guarded by a lock.

In other cases you can (theoretically) face the situation when result of new will be avaiable to other threads before completion of constructor call (due to possible operation reordering).

Note, however, that if 0 is a default value rather than the value written in the constructor, it's guaranteed to be visible (JLS §17.4.4):

  • The write of the default value (zero, false or null) to each variable synchronizes- with the first action in every thread. Although it may seem a little strange to write a default value to a variable before the object containing the variable is allocated, conceptually every object is created at the start of the program with its default initialized values


From Java Concurrency in Practice:

Objects that are not immutable must be safely published, which usually entails synchronization by both the publishing and the consuming thread.

An object is not safely published just by not publishing its reference in the constructor. I.e. the constructor does not enforce the necessary happens-before relationship. So, even if you don't publish an object reference within its constructor, you can still have concurrency problems. For details and examples, see the relevant chapter in the book.

In order to do a safe publication, the authors suggest the following ways:

To publish an object safely, both the reference to the object and the object's state must be made visible to other threads at the same time. A properly constructed object can be safely published by:

Initializing an object reference from a static initializer;

Storing a reference to it into a volatile field or AtomicReference;

Storing a reference to it into a final field of a properly constructed object; or

Storing a reference to it into a field that is properly guarded by a lock. In essence, a proper "happens-before" relationship must be introduced between construction of the object and accessing of that object by another thread.

As the authors note, objects that are passed through threadsafe collections are also safely published (e.g. item passed through a worker thread through LinkedBlockingQueue etc.).

It is true that storing a value to primitive int fields (but not to 64bit fields like long) are atomic, meaning that you cannot observe a "weird" value even if you access that field in a non-thread-safe way from a different thread. But when an object is not yet properly constructed, other bad things may happen (to be honest I don't know what exactly could happen, but it's surely not worth a try).

To summarize, you need to publish the object safely anyways, at which point the value is correctly set to 0 and the object is properly instantiated.

0

精彩评论

暂无评论...
验证码 换一张
取 消