Why can't Java constructors be synchronized?

JavaConstructorLanguage DesignSynchronized

Java Problem Overview


According to the Java Language Specification, constructors cannot be marked synchronized because other threads cannot see the object being created until the thread creating it has finished it. This seems a bit odd, because I can indeed have another thread view the object while it's being constructed:

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

I know that this is a pretty contrived example, but it seems in theory that someone could come up with a more realistic case where marking the constructor synchronized would be legitimate in order to prevent races with threads like this one.

My question is this: is there a reason that Java would specifically disallow the synchronized modifier on a constructor? Perhaps my above example is flawed, or perhaps there really is no reason and it's an arbitrary design decision. In either case, I'm really curious and would love to know the answer.

Java Solutions


Solution 1 - Java

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.

Solution 2 - Java

The question has been raised on a discussion list used by the writers of the Java concurrent API and the Java Memory Model. Several answers were given, in particular Hans Boehm replied:

> Some of us (myself included IIRC) actually argued during the Java memory model deliberations that synchronized constructors should be allowed. Now I could go either way on it. Client code shouldn't use races to communicate the reference, so it shouldn't matter. But if you don't trust the clients of [your class], I think synchronized constructors could possibly be useful. And that was much of the reasoning behind final field semantics. [...] As David said, you can use synchronized blocks.

Solution 3 - Java

Because synchronized guarantees that actions on the same objects are not to be performed by multiple threads. And when the constructor is called you still don't have the object. It is logically impossible for two threads to access the constructor of the same object.

In your example, even if a method is invoked by the new thread, it is no longer about the constructor - it is about the target method being synchronized or not.

Solution 4 - Java

In your example, the constructor is only actually called once from one thread.

Yes, it is possible to get a reference to an incompletely constructed Object (some discussions around double check locking and why it is broken reveal this problem), however, not by calling the constructor a second time.

Syncronized on the constructor would prevent two threads from calling the constructor on the same Object simultaneously, and that is not possible, as it is never possible to call the constructor on an object instance twice, period.

Solution 5 - Java

Constructor Modifiers section in JLS clearly says

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 there is no need for constructor to be synchronized.

Also it is not recommended to give out the objects reference(this) before object is created. One of the possible ambiguous situations would be to give out the objects reference is superclass constructor when subsclass object is being created.

Solution 6 - Java

I see little reason to forbid constructors to be synchronized. It would be useful in many scenarios in multi-threaded applications. If I understand the Java Memory Model correctly (I read http://jeremymanson.blogspot.se/2008/11/what-volatile-means-in-java.html) the following simple class could have benefited from a synchronized constructor.

public class A {
    private int myInt;
    
    public /*synchronized*/ A() {
        myInt = 3;
    }
    
    public synchronized void print() {
        System.out.println(myInt);
    }
}

In theory, I believe a call to print() could print "0". This could happen if an instance of A is created by Thread 1, the reference to the instance is shared with Thread 2, and Thread 2 calls print(). If there is no special synchronization between the write myInt = 3 of Thread 1 and the read of the same field by Thread 2, Thread 2 is not guaranteed to see the write.

A synchronized constructor would fix this issue. Am I right about this?

Solution 7 - Java

The following code can achieve the expected result for synchronized constructor.

public class SynchronisedConstructor implements Runnable {

	private int myInt;

	/*synchronized*/ static {
		System.out.println("Within static block");
	}

	public SynchronisedConstructor(){
		super();
		synchronized(this){
			System.out.println("Within sync block in constructor");
			myInt = 3;
		}
	}

	@Override
	public void run() {
		print();
	}

    public synchronized void print() {
    	System.out.println(Thread.currentThread().getName());
        System.out.println(myInt);
    }

    public static void main(String[] args) {
	
    	SynchronisedConstructor sc = new SynchronisedConstructor();
	
		Thread t1 = new Thread(sc);
		t1.setName("t1");
		Thread t2 = new Thread(sc);
		t2.setName("t2");
	
		t1.start();
		t2.start();
	}
}

Solution 8 - Java

Such a synchronization might make sense in some very rare cases, but I guess, it's just not worth it:

  • you can always use a synchronized block instead
  • it'd support coding in a pretty strange way
  • on what should it synchronize? A constructor is a sort-of static method, it works on an object but gets called without it. So synchronizing on the class also makes (some) sense!

When in doubt, leave it out.

Solution 9 - Java

Note that constructors cannot be synchronized — using the synchronizedkeyword with a constructor is a syntax error. Synchronizing constructors doesn't make sense, because only the thread that creates an object should have access to it while it is being constructed.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiontemplatetypedefView Question on Stackoverflow
Solution 1 - JavaPaŭlo EbermannView Answer on Stackoverflow
Solution 2 - JavaassyliasView Answer on Stackoverflow
Solution 3 - JavaBozhoView Answer on Stackoverflow
Solution 4 - JavaYishaiView Answer on Stackoverflow
Solution 5 - JavaAniket ThakurView Answer on Stackoverflow
Solution 6 - JavaFrans LundbergView Answer on Stackoverflow
Solution 7 - JavaNimeshView Answer on Stackoverflow
Solution 8 - JavamaaartinusView Answer on Stackoverflow
Solution 9 - JavasarirView Answer on Stackoverflow