Why can't Java constructors be synchronized?
Asked Answered
H

9

70

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.

Hetti answered 2/2, 2011 at 21:39 Comment(7)
As an aside, it is highly recommended not to allow the "this" reference to escape before the constructor has completed.Agglutinin
@Mike Q- I've heard this before but don't fully understand why. Is there a particular reason why? I could see Bad Things happening if you gave out a reference to this before you finished initializing the object, but what if it's the last thing you do in the constructor?Hetti
it is really the subject of another question, but even if it is the last thing you do in the constructor, if the object is subclassed, then the subclass has not finished constructing. If this class is final, and you don't chain constructors (calling this(...)) and do something else after the chain call and it is the last thing you do, its fine. Except of course that any of those decisions could change (you could add a second constructor later).Dialectics
It's much clearer if you quote what the JLS actually 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."Guesthouse
see ibm.com/developerworks/java/library/j-jtp0618.html for more detailsAgglutinin
From the Java Tutorial (link) "Warning: When constructing an object that will be shared between threads, be very careful that a reference to the object does not "leak" prematurely. For example, suppose you want to maintain a List called instances containing every instance of class. You might be tempted to add the following line to your constructor: instances.add(this); But then other threads can use instances to access the object before construction of the object is complete."Repel
In addition to the previous comment, the Java Tutorial says, in the same lesson, that you cannot use the 'synchronized' keyword in a constructor, and then it states the warning in the previous comment. This seems contradictory to me, and I hope that, in the future, constructors will be synchronized by default on the object just created. That's what seems the most reasonable choice IMHO, since otherwise you are accessing an object in inconsistent state.Repel
M
33

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.

Mcglothlin answered 2/2, 2011 at 21:50 Comment(4)
@Paulo, your example is highly contrived. First, it would be a bad practice to call an abstract method from a constructor, but more importantly, if there was no threading going on the subclass would have exactly the same problem. So syncronized would add what? Support for a highly unlikely case while causing the subclass to anyway have to work around the much more common case in a way that could have worked for both cases.Dialectics
@Yishai: You are right, the example is not so realistic. But I've seen classes who publish their own objects in the constructor to other threads (not necesarily in the same class, and not necesarily with a sleep), and then you can have such problems where a synchronized constructor could help. Of course, this method in my example should guard itself for being called from the superclass constructor.Longlived
Im not convinced this is a good example either, primarily because its bad practice to start a thread inside of a constructor.Pili
@MandeepRajpal Thanks for the edit proposal, but the first example doesn't need the abstract. The second one actually needed it, though – I've added it here.Longlived
C
18

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.

Calcify answered 5/8, 2013 at 5:56 Comment(2)
I am not getting, how it makes sense even to discuss whether language should allow it or not, especially when others are saying it does not makes sense because "when the constructor is called you still don't have the object (to synchronize on)". So I feel its simply impossible to even implement by the language. Or there is something which I am missing?Eolanda
@anir imagine a static MyObject o; - thread 1 executes o = new MyObject(); while thread 2 calls o.getSomething();. There is a race condition and thread 2 could observe a partially constructed object. If both the constructor and getSomething were synchronized, you would have the guarantee to see the object in a consistent state. Hence the comment in the quote above "Client code shouldn't use races to communicate the reference, so it shouldn't matter.".Calcify
H
9

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.

Hannahannah answered 2/2, 2011 at 21:43 Comment(12)
You are correct that two threads can't both call the constructor, but what if one thread calls the constructor, which then fires off another thread that tries to invoke a different synchronized method of the class? In that case, having a synchronized constructor would prevent the second thread from invoking any synchronized methods until the constructor terminated.Hetti
it's not about the constructor anymore, but about the method in question.Hannahannah
They you can do a synchronized(this) {} inside your constructor. Synchronized on the constructor itself is a nonsense. How do you acquire the mutex to an object prior to starting the process of bringing it into existence?Michelmichelangelo
The JVM code for creating an object is two steps - allocating the object with all fields default-initialized, then calling the constructor. In that interim step it seems perfectly reasonable to set up the object's monitor, which could allow the constructor to be marked synchronized.Hetti
@Hetti the constructor is already invoked. You can't invoke the constructor of this object again. You can invoke methods there, but methods have synchronizedHannahannah
(I was not the downvoter.) The explanation by templatetypedef make sence: If you don't want a synchronized method of your class (or any sub- or superclass) to be executed by another thread before your constructor is finished, and maybe even the superclass constructor publishes your object, you have lost – even a synchronized block in the constructor (like in my answer) does not help, since it does not apply to the superclass constructor.Longlived
@Paŭlo Ebermann as I said - if you want to synchronize methods, well, synchronize the methods - the constructor has nothing to do with it.Hannahannah
It has, if you want to avoid that these methods are executed concurrently with the constructor. Making only the methods synchronized does not help here. This is (now) only possible when you use a synchronized block inside your constructor, which still does not help for the superclass constructor.Longlived
@Paŭlo Ebermann now imagine your example, but with a method. it's the same scenario - you have two methods that need to synchronize their execution. It is completely different scenario from the synchronized signature modifierHannahannah
(I'll add a example to my answer, since here in the comments I can't really post code.)Longlived
@Hannahannah your comments are irrelevant to templatetypedef's comment. Template is talking about the bytecode level, where it is in fact possible to do some operations on unitialized objects, and pointing out that the VM could conceivably be designed so that you can synchronize on uninitialized objects as well.Conal
I think (it was a long time ago) that I meant the following: even if it is two steps: initialization and invoking constructor, and other threads can see the initialized object, they can't invoke the 2nd step on it. On the JVM level they probably can, but you can't express that in Java codeHannahannah
Y
7

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.

Yearround answered 4/9, 2013 at 4:17 Comment(1)
You could syncrhonize on something else.Unseal
D
5

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.

Dialectics answered 2/2, 2011 at 21:49 Comment(1)
I did not downvote, but a possible reason: synchronized on the constructor would not only avoid two threads calling the constructor of the same thread (which is impossible anyway), but also avoid calling a synchronized method of this object (or entering a synchronized block with this object as a parameter) in another thread.Longlived
D
4

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?

Distich answered 22/1, 2013 at 11:20 Comment(6)
(i) the problem you describe is that the instance of A is not properly published, in which case its observed state could be anything indeed (ii) you could write synchronized (this) { myInt = 3; } in your constructor to solve the issue, or mark myInt as final.Calcify
You can also mark myInt variable with volatile keyword.Harmattan
Not necessarily. If reference of the object is leaked to some other thread before it's fully constructed, then the other thread can call non-synchronized method of this object as well, in which case synchronizing the constructor never helps. Avoiding the later case means no leakage should be practiced, thereafter synchronizing the constructor becomes unnecessary.Nica
No. In your case, Thread 1 would not have an instance of A until its constructor had completed, so it would not be able to share it with Thread 2. Even if it were possible, you could simply wrap the constructor code inside a synchronized block and get the same effect.Dalton
This has nothing to to with leaking this in the constructor, more with what the JIT/optimizer does. - It is allowed to re-order stuff but not beyond sync-actions. So without the constructor sync, the constructor can return but the myInt field still lives in a register, not in memory. So the other thread ready a 0.Endamage
I agree this answer gives a plain and obvious use case for synchronized constructors. To summarize the use case: you have a field that's initialized in the constructor, the field is not final, and you simply want the field to be read correctly (from the fully constructed object) at some later time by another thread. What's contrived about that?? Yes, a synchronized block is a workaround, but that's no counter-argument - otherwise you would also have to accept getting rid of synchronzed methods.Black
A
0

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();
    }
}
Anthill answered 13/2, 2013 at 5:27 Comment(0)
O
0

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.

Orthogenic answered 21/10, 2017 at 14:26 Comment(0)
P
0

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.

Prima answered 15/11, 2018 at 16:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.