当前位置: 首页 > 面试题库 >

为什么Java构造函数无法同步?

廉飞捷
2023-03-14
问题内容

根据Java语言规范,无法将构造函数标记为已同步,因为其他线程在创建该对象的线程完成之前无法看到正在创建的对象。这似乎有些奇怪,因为在构造对象时,我确实可以让另一个线程查看该对象:

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

我知道这是一个非常人为的示例,但从理论上讲,似乎有人可以提出一个更现实的案例,在该案例中,标记构造函数为同步状态是合法的,以防止此类线程的竞争。

我的问题是:Java是否有理由特别禁止在构造函数上使用synced修饰符?也许我上面的例子有缺陷,或者也许真的没有理由,这是一个任意的设计决定。无论哪种情况,我都很好奇,很想知道答案。


问题答案:

如果您确实需要将构造函数的其余部分与任何线程进行同步,而这些线程无论如何都能引用尚未完全构造的对象,则可以使用synced-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
       }
    }
}

通常,这样“放弃”尚未构造的对象被认为是不好的风格,因此不需要同步的构造函数。

在某些特殊情况下,同步构造函数会很有用。通过讨论博佐的答案,这是一个更现实的示例:

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()仅在构造完SubClass对象后才调用该方法,例如,我们只希望“一切正常”输出。但是在这种情况下,当您只能编辑子类时,您将没有机会实现这一目标。如果构造函数可以同步,则可以解决问题。

因此,我们从中学到的知识是:如果您的类不是final的,则永远不要像我在超类构造器中所做的那样做-并且不要从构造函数中调用您自己类的任何非最终方法。



 类似资料:
  • 问题内容: Java为什么不支持C ++中的复制构造函数? 问题答案: Java。只是没有像在C ++中那样隐式地调用它们,我怀疑这是您的真正问题。 首先,复制构造函数无非是: 现在,C ++将使用以下语句隐式调用复制构造函数: 在这种情况下,克隆/复制在Java中根本没有意义,因为所有b1和b2都是引用,而不是像C 中那样的值对象。在C 中,该语句复制对象的状态。在Java中,它只是复制 引用

  • 问题内容: 在C ++中,从构造函数内部调用虚拟函数时,它的行为不像虚拟函数。 我认为第一次遇到这种行为的每个人都会感到惊讶,但第二次认为这是有道理的: 只要派生的构造函数没有被执行的对象是 不是 又一个 衍生 实例。 那么如何调用派生函数呢?前提条件还没有建立的机会。例: Java和.NET完全相同,但是他们选择了另一种方式,这可能是 产生最少惊讶原则 的唯一原因吗? 您认为哪个是正确的选择?

  • 本文向大家介绍请解释Java中的概念,什么是构造函数?什么是构造函数重载?什么是复制构造函数?相关面试题,主要包含被问及请解释Java中的概念,什么是构造函数?什么是构造函数重载?什么是复制构造函数?时的应答技巧和注意事项,需要的朋友参考一下 考察点:JAVA构造函数 当新对象被创建的时候,构造函数会被调用。每一个类都有构造函数。在程序员没有给类提供构造函数的情况下,Java编译器会为这个类创建一

  • 问题内容: 我的一项作业需要一个银行帐户才能从支票和储蓄帐户转帐资金。交易存储在ArrayList中,并设置为用户指定何时转移资金。用于支票和储蓄的银行帐户类可以正常工作,但是我创建的TransferService类在NetBeans中不能正确编译。 这些提示似乎无法解决错误。我得到错误: 事务是抽象的,无法实例化。 我该如何解决这个问题? 问题答案: 构造函数没有返回类型。所以不 反而 关于,

  • 问题内容: 我是Java编程语言的初学者,最近我研究了 构造函数 不能在Java中继承,有人可以解释 为什么 吗? 问题答案: 简而言之,构造函数不能被继承,因为在子类中它具有​​不同的名称(子类的名称)。 您只能执行以下操作: 相反,方法是使用“相同名称”继承的,可以使用。 理由如下:继承构造函数没有多大意义,因为类A的构造函数意味着创建类型A的对象,而类B的构造函数意味着创建类B的对象。 不过

  • 当Java中给出参数构造函数时,为什么默认的无参数构造函数会失败? 这个设计有什么意义? 例如: