java—是否需要同步构造函数中的块?

mmvthczy  于 2021-07-08  发布在  Java
关注(0)|答案(2)|浏览(408)

这个问题并没有回答必要部分:构造函数中的同步块。
鉴于这句格言
jvm一次不允许多个线程调用类的构造函数

问题a

意思是?
jvm将不允许多个线程调用类的任何构造函数
这样即使一个类中有多个构造函数,一个类一次也只能由一个线程示例化。
如果一个类有多个构造函数,那么每个构造函数一次只能由一个线程调用
这样,如果一个类有三个构造函数,那么三个线程可以同时示例化该类。
在我看来,#1是问题1的答案是合乎逻辑的。

问题b

如果questiona.answer#1为真,是否意味着在构造函数中有同步块是毫无意义的?
例如,假定setbrandaccessor方法只由构造函数调用,那么是否不需要同步setbrandaccessor方法?如有必要,请解释原因。

class DataAccessor {
  static Brand brandAccesor;

  DataAccessor(Brand brand) {
    super(brand);
    setBrandAccessor(Brand brand);
  }

  private synchronized setBrandAccessor(Brand brand) {
    if (brandAccessor==null) brandAccessor=brand;
  }
}
s71maibg

s71maibg1#

jvm一次不允许多个线程调用类的构造函数
这不是真的,多个线程可以同时调用构造函数。我不知道你从哪里得到这句格言的。
问题a
两者都不是真的,格言本身是不正确的。
问题b
这并不是你想的那样。 setBrandAccessor 将在上同步 this ,这对于每个构造函数都是不同的,因此该方法将不会以您期望的方式进行同步,实际上与根本不同步它是一样的。你可以这样做:

class DataAccessor {
  static Object lock = new Object();
  static Brand brandAccesor;

  DataAccessor(Brand brand) {
    super(brand);
    synchronized(lock) {
        if (brandAccessor==null) brandAccessor=brand;
    }
  }
}

class DataAccessor {
  static Brand brandAccesor;

  DataAccessor(Brand brand) {
    super(brand);
    setBrandAccessor(Brand brand);
  }

  // Being static synchronized is the same as synchronizing on a static object
  private static synchronized setBrandAccessor(Brand brand) {
    if (brandAccessor==null) brandAccessor=brand;
  }
}

这看起来确实有点反模式。如果你不能更好的组织你的代码,我会很惊讶,但是如果没有更多的上下文很难评论。

eyh26e7m

eyh26e7m2#

问题a:两个线程可以同时构造一个对象,并行运行构造函数。两个线程不能同时构造同一个对象。这两个线程将构造两个不同的对象。构造函数在两个不同的对象上运行,这就消除了对同步块的最大需求之一。
问题b:构造函数中的同步块并非毫无意义:构造函数可以访问其他类或静态变量中的可变共享状态,而同步块是保证互斥的一种方法。
关于 setBrandAccessor 在中(请注意,我已删除静态修饰符,使字段成为示例字段):

class DataAccessor {
  Brand brandAccesor;

  DataAccessor(Brand brand) {
    super(brand);
    setBrandAccessor(brand);
  }

  private synchronized setBrandAccessor(Brand brand) {
    brandAccessor=brand;
  }
}

如果您使用的是来自其他线程的此类对象,则可能需要同步该方法。您需要保证在另一个线程中正在写入的字段和正在读取的字段之间有一个“发生在”边,而不管“写入”是否发生在构造函数中。制造 get 以及 set 同步方法保证了适当的多线程可见性。
另一种保证多线程可见性的方法是删除set方法并使字段 final .

final Brand brandAccesor;

  DataAccessor(Brand brand) {
    super(brand);
    brandAccessor=brand;
  }

相关问题