Constructor Synchronization in Java

Why can't Java constructors be synchronized?

If you really need synchronization of the rest of the constructor versus any threads which anyhow gets a reference to your not-yet-totally-constructed object, you can use a synchronized-block:

public class Test {
public Test() {
final Test me = this;
synchronized(this) {
new Thread() {
@Override
public void run() {
// ... Reference 'me,' the object being constructed
synchronized(me) {
// do something dangerous with 'me'.
}
}
}.start();
// do something dangerous with this
}
}
}

Usually it is considered bad style to "give out" your not-yet-constructed object like this, so a synchronized constructor is not necessary.


In some corner cases a synchronized constructor would be useful. Here is a more realistic example, from the discussion of Bozho's answer:

public abstract class SuperClass {

public SuperClass() {
new Thread("evil") { public void run() {
doSomethingDangerous();
}}).start();
try {
Thread.sleep(5000);
}
catch(InterruptedException ex) { /* ignore */ }
}

public abstract void doSomethingDangerous();

}

public class SubClass extends SuperClass {
int number;
public SubClass () {
super();
number = 2;
}

public synchronized void doSomethingDangerous() {
if(number == 2) {
System.out.println("everything OK");
}
else {
System.out.println("we have a problem.");
}
}

}

We want that the doSomethingDangerous() method is only called after construction of our SubClass object is complete, e.g. we only want the "everything OK" output. But in this case, when you only can edit your SubClass, you have no chance of achieving this. If the constructor could be synchronized, it would solve the problem.

So, what we learn about this: never do something like I did here in the superclass constructor, if your class is not final - and don't call any non-final methods of your own class from your constructor.

Synchronization in Constructors to make it Happens-before

If the object is safely published (for instance, by instantiating it as someVolatileField = new Foo()), then you don't need synchronization in the constructor. If it's not, then synchronization in the constructor is not enough.

There was a somewhat lengthy discussion on the java concurrency-interest list a few years back about this; I'll provide the summary here. (Full disclosure: I started that discussion, and was involved throughout it.)

Remember that the happens-before edge only applies between one thread releasing the lock, and a subsequent thread acquiring it. So, let's say you have:

someNonVolatileField = new Foo();

There are are three significant sets of actions here:

  1. the object being allocated, with all its fields set to 0/null
  2. the constructor running, which includes an acquire and release of the object's monitor
  3. the object's reference being assigned to someNonVolatileField

Let's say another thread then uses the reference, and calls a synchronized doFoo() method. Now we add two more actions:


  1. reading the someNonVolatileField reference
  2. invoking doFoo(), which includes an acquire and release of the object's monitor

Since the publication to someNonVolatileField wasn't safe, there is a lot of reordering that the system can do. In particular, the reading thread is allowed to see things happening in this order:

  1. the object being allocated, with all its fields set to 0/null
  2. the object's reference being assigned to someNonVolatileField
  3. reading the someNonVolatileField reference
  4. invoking doFoo(), which includes an acquire and release of the object's monitor
  5. the constructor running, which includes an acquire and release of the object's monitor

In this case, there's still a happens-before edge, but goes the other way around from what you want. Specifically, the call to doFoo() formally happens-before the constructor.

This does buy you a little bit; it means that any synchronized method (or block) is guaranteed to see either the full effects of the constructor, or none of those effects; it won't see only part of the constructor. But in practice, you probably want to guarantee that you see the effects of the constructor; that's why you wrote the constructor, after all.

You can get around this by having doFoo() not be synchronized, and instead set up some spin-loop waiting for a flag that says the constructor has run, followed by a manual synchronized(this) block. But by the time you get to that level of complexity, it's probably better to just say "this object is thread safe assuming its initial publication was safe." That's the de-facto assumption for most mutable classes that bill themselves as thread-safe; immutable ones can use final fields, which is thread-safe even in the face of unsafe publication, but which doesn't require explicit synchronization.

Constructor synchronization in Java

Someone somewhere told me that Java constructors are synchronized so that it can't be accessed concurrently during construction

This is certainly not the case. There is no implied synchronization with constructors. Not only can multiple constructors happen at the same time but you can get concurrency issues by, for example, forking a thread inside of a constructor with a reference to the this being constructed.

if I have a constructor that stores the object in a map, and another thread retrieves it from that map before its construction is finished, will that thread block until the constructor completes?

No it won't.

The big problem with constructors in threaded applications is that the compiler has the permission, under the Java memory model, to reorder the operations inside of the constructor so they take place after (of all things) the object reference is created and the constructor finishes. final fields will be guaranteed to be fully initialized by the time the constructor finishes but not other "normal" fields.

In your case, since you are putting your Test into the synchronized-map and then continuing to do initialization, as @Tim mentioned, this will allow other threads to get ahold of the object in a possibly semi-initialized state. One solution would be to use a static method to create your object:

private Test() {
this.id = atomicIdGenerator.getAndIncrement();
// Some lengthy operation to fully initialize this object
}

public static Test createTest() {
Test test = new Test();
// this put to a synchronized map forces a happens-before of Test constructor
testsById.put(test.id, test);
return test;
}

My example code works since you are dealing with a synchronized-map, which makes a call to synchronized which ensures that the Test constructor has completed and has been memory synchronized.

The big problems in your example is both the "happens before" guarantee (the constructor may not finish before Test is put into the map) and memory synchronization (the constructing thread and the get-ing thread may see different memory for the Test instance). If you move the put outside of the constructor then both are handled by the synchronized-map. It doesn't matter what object it is synchronized on to guarantee that the constructor has finished before it was put into the map and the memory has been synchronized.

I believe that if you called testsById.put(this.id, this); at the very end of your constructor, you may in practice be okay however this is not good form and at the least would need careful commenting/documentation. This would not solve the problem if the class was subclassed and initialization was done in the subclass after the super(). The static solution I showed is a better pattern.

Should I synchronize constructor?

As per the JLS#8.8.3

There is no practical need for a constructor to be synchronized,
because it would lock the object under construction, which is normally
not made available to other threads until all constructors for the
object have completed their work.

So that implies the reference is being synchronized prior to be accessible.

Since you are correctly synchronizing, it would be said writes that occur in the constructor would happen-before the object is published, so long as the synchronization is consistent on said field

In your case since getX() and setX() are both synchronized, the synchronization is consistent and you do not need to sync in the constructor.


Now, would you ever need to synchronize(this) on the constructor? No, as the JLS mentions it is implicitly synchronizing without you knowing about it.

Can we call synchronized method of an object inside the constructor of the object in Java?

You can do that but that synchronization is meaningless because the synchronized method will lock the instance that is currently being created. But which other thread could access it while that has not still be created and returned ? No one.

Constructors are indeed defacto thread safe as long as you follow good practices such as not passing this to other classes/objects inside the constructor body.

Your example could make more sense with a synchronized static method or synchronized on a static field.

How I can make my constructor synchronized?

You don't synchronize a constructor, that doesn't make any sense semantically, you synchronize the access to the variable. Which can happen from anywhere that has access to it.

What you are looking for in this case is AtomicInteger.

Do accesses in a constructor to a shared static variable need to be synchronized?

Absolutely - after all, it's accessing a shared resource, potentially via many threads. I would personally just use an AtomicInteger instead.

public class MyClass {
private static final AtomicInteger count = new AtomicInteger();

public MyClass() {
count.incrementAndGet();
}
}

Note that we can now make the variable final as that variable doesn't change value, and we don't need to synchronize any more as the whole point of the classes in java.util.concurrent.atomic is that they can be used atomically without extra synchronization.

Even if you are in the situation where you need to synchronize, I wouldn't use MyClass.class to do so - that's a reference which other code might decide to synchronize on, so you can't really reason about your code any more. I would write (again, only if AtomicInteger wasn't good enough for some reason):

public class MyClass {
private static final Object countLock = new Object();
private static int count = 0;

public MyClass() {
synchronized(countLock) {
count++;
}
...
}
}

(In this case you'd also want to synchronize on countLock anywhere else you access count, even just for reading.)



Related Topics



Leave a reply



Submit