Publish an object through the constructor

Consider the following class:

class Ideone { private Map<String, String> m; public Ideone(){ synchronized(this){ m = new ConcurrentHashMap<>(); } } public synchronized Map<String, String> getM(){ return Collections.unmodifiableMap(m); //effectively immutable } } 

In order for other classes to observe the internal state of Ideone , we must safely publish its internal state (with proper synchronization). If we do not, this does not guarantee that another thread will read the correct value (and not the default). For example:

 public volatile Ideone ideone; public void init(){ ideone = new Ideone(); } 

I think that if we did not synchronize the construct and getter, for example

 class Ideone { private Map<String, String> m; public Ideone(){ m = new ConcurrentHashMap<>(); } public Map<String, String> getM(){ return Collections.unmodifiableMap(m); //effectively immutable } } 

there would be no guarantee that the correct state value was maintained (for example, the default value).

But, as said in this answer , such synchronization is undesirable if it allows this to escape.

QUESTION: Why does synchronization in the constructor allow this to escape?

0
java multithreading synchronization
source share
2 answers

The answer implied that the only reason for using synchronize(this) was for the case when the this reference escaped from the constructor.

But this reasoning is wrong. I added another answer to this question: stack overflow

You showed a case where at first glance, using synchronized(this) in the constructor is reasonable, because it really ensures that getM() will have the correct value for the instance variable m when called from another thread.

And if you didn’t have these synchronized blocks, it would not be necessary - it is possible for another thread to see the null value for the field m even after the constructor completes, because it didn’t happen - until the relationship between assigning m in the constructor in the same thread and reading m in the getM method in another thread.

But : how did you transfer the Ideone instance from one thread to another thread? If you did this in a field without any synchronization mechanism, so without any action - before the relationship, then the second thread does not guarantee that the entire instance of Ideone completely absent.

If it sees an instance, then the data in the instance, if they are true, but in this case can also see null .

However, if you used a synchronization mechanism to transfer an instance of Ideone , then this mechanism already created a connection between events and then, and using synchronized in the constructor and getM not necessary anymore.

And since all the safe mechanisms for transferring objects between threads are connected with the synchronization mechanism, which establishes a connection between events, then (almost) you never need to do what you do with synchronized in the constructor.

+1
source share

You misunderstood the answer.

It is clear that synchronized(this) does inside the constructor .

For a synchronized(this) statement, which should be useful, two threads must have access to a synchronized block with the same object at the same time.

Now one of the threads is inside the constructor, which means that the object is only being created ...

And for some other thread, to have a reference to this object, you had to leak the current object ( this ) from the constructor in some place .

Your code does not leak, but again synchronized(this) has no meaning inside the constructor in your code.

+2
source share

All Articles