Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
190 views
in Technique[技术] by (71.8m points)

Why can't Java constructors be synchronized?

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...