Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java non-final int(s) visible after construction

I have a java class with a non-final int 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?

like image 399
richs Avatar asked Mar 14 '11 13:03

richs


2 Answers

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
like image 84
axtavt Avatar answered Nov 17 '22 22:11

axtavt


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.

like image 43
Enno Shioji Avatar answered Nov 17 '22 23:11

Enno Shioji