根据Java语言规范 http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.8.3,构造函数不能标记为同步,因为在创建该对象的线程完成之前,其他线程无法看到正在创建的对象。这看起来有点奇怪,因为我确实可以让另一个线程在构造对象时查看该对象:
public class Test {
public Test() {
final Test me = this;
new Thread() {
@Override
public void run() {
// ... Reference 'me,' the object being constructed
}
}.start();
}
}
我知道这是一个非常人为的示例,但从理论上讲,似乎有人可以提出一种更现实的情况,其中将构造函数标记为同步是合法的,以防止与这样的线程发生竞争。
我的问题是:Java 是否有明确禁止在构造函数上使用同步修饰符的原因?也许我上面的例子是有缺陷的,或者也许真的没有理由,这是一个任意的设计决定。无论哪种情况,我都很好奇并且很想知道答案。
如果您确实需要同步构造函数的其余部分与任何获取对尚未完全构造的对象的引用的线程,则可以使用同步块:
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
}
}
}
通常,像这样“给出”尚未构造的对象被认为是不好的风格,因此不需要同步构造函数。
在某些极端情况下,同步构造函数会很有用。这是一个更现实的例子,来自 Bozho 答案的讨论:
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.");
}
}
}
我们希望doSomethingDangerous()
方法仅在子类对象的构造完成后调用,例如我们只想要“一切正常”的输出。但在这种情况下,当你只能编辑你的子类时,你就没有机会实现这一点。如果构造函数可以同步的话,问题就解决了。
因此,我们了解到:如果您的类不是最终类,则永远不要在超类构造函数中执行类似我在此处所做的操作 - 并且不要从构造函数中调用您自己的类的任何非最终方法。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)