某个地方的人告诉我Java构造函数是同步的,因此在构造过程中不能同时访问它,而我在想:是否有构造函数将对象存储在映射中,而另一个线程在构造之前从该映射检索它完成后,该线程是否会阻塞,直到构造函数完成?
让我用一些代码演示:
public class Test {
private static final Map<Integer, Test> testsById =
Collections.synchronizedMap(new HashMap<>());
private static final AtomicInteger atomicIdGenerator = new AtomicInteger();
private final int id;
public Test() {
this.id = atomicIdGenerator.getAndIncrement();
testsById.put(this.id, this);
// Some lengthy operation to fully initialize this object
}
public static Test getTestById(int id) {
return testsById.get(id);
}
}
假设put / get是地图上唯一的操作,因此我不会通过迭代之类的方法来获取CME,并尝试在此忽略其他明显的缺陷。
我想知道的是,如果另一个线程(显然不是构造该对象的线程)试图使用getTestById
并调用对象来访问该对象,它将阻塞吗?换一种说法:
Test test = getTestById(someId);
test.doSomething(); // Does this line block until the constructor is done?
我只是想弄清楚构造函数同步在Java中进行的程度,以及类似的代码是否有问题。我最近看到这样的代码而不是使用静态工厂方法来执行此操作,并且我想知道在多线程系统中这样做有多危险(或安全)。
某人告诉我Java构造函数是同步的,因此在构造过程中不能同时访问它
当然不是这样。没有与构造函数的隐含同步。不仅可以同时发生多个构造函数,而且还可以通过(例如)在构造函数内部派生一个引用this
所构造对象的线程来解决并发问题。
如果我有一个将对象存储在映射中的构造函数,并且另一个线程在构造完成之前从该映射中检索了该对象,那么该线程是否会阻塞直到构造函数完成?
不,不会。
在线程应用程序的构造函数的一个大问题是,编译器有权限,Java的内存模型下,重新排序构造内的操作,使他们发生 后 (万物)创建对象的引用和构造完成。
final
可以保证在构造函数完成时,字段会完全初始化,而其他“普通”字段则不会。
在您的情况下,由于您将自己Test
放入synced -map中, 然后
继续进行初始化(如@Tim所述),因此这将允许其他线程在可能处于半初始化状态的情况下保留该对象。一种解决方案是使用一种static
方法来创建您的对象:
private Test() {
this.id = atomicIdGenerator.getAndIncrement();
// Some lengthy operation to fully initialize this object
}
public static Test createTest() {
Test test = new Test();
// this put to a synchronized map forces a happens-before of Test constructor
testsById.put(test.id, test);
return test;
}
我的示例代码可以正常工作,因为您正在处理同步映射,该映射进行调用以synchronized
确保Test
构造函数已完成并且已进行内存同步。
您的示例中的主要问题是“先发生”保证(构造函数在Test
放入映射中之前可能未完成)和内存同步(构造线程和获取线程可能会为Test
实例看到不同的内存)。如果将put
构造函数移到外部,则两者都将由synced-
map处理。不管使用什么对象synchronized
,以确保构造函数在放入映射之前已经完成并且内存已同步。
我相信,如果你叫testsById.put(this.id, this);
的 非常
构造函数结束时,你可以在实践中是好的但是这不是好的形式,并在至少需要小心注释/文档。如果类被子类化,并且在子类之后进行了初始化,这将无法解决问题super()
。static
我展示的解决方案是更好的模式。
本文向大家介绍Java构造函数,包括了Java构造函数的使用技巧和注意事项,需要的朋友参考一下 构造函数与方法相似,但在以下方面有所不同。 它们没有任何返回类型。 构造函数的名称与类的名称相同。 每个类都有一个构造函数。如果我们未为类明确编写构造函数,则Java编译器将为该类建立默认构造函数。 每次创建一个新对象时,将至少调用一个构造函数。 一个类可以具有多个构造函数。 示例 输出结果
问题内容: 我知道我在这里问一些严重的101问题… 我有一些课,还有一个延伸课。在我有一个构造函数,它接受一组参数,并对其字段进行设置。派生类(例如)通常不需要进行修改。现在我的IDE给我 “ Foo中没有默认的构造函数” 。从一点点谷歌搜索,这似乎是因为“构造函数没有继承”。因此,一切都很好,但是我现在如何使它工作而不在每个派生类中复制此构造函数?我假设有一个更合理的方法? 问题答案: 使用构造
实际上,我不明白无参数构造函数和默认构造函数的区别是什么。 在创建名为cFrame的Test对象时,是否调用此类的默认构造函数?
我有一个抽象的超类,它有一个形式的构造函数 并希望创建该抽象类的一个子类,该子类不是以字符串作为其第一个参数,而是采用一个表示给定字符串名称的整数值,例如,0代表某个字符串,1代表另一个字符串,依此类推。 当我尝试编写窗体子类(int number,int amount)的构造函数时,我得到一个格式为“Implicit super constructor is undefined.必须显式调用另一
问题内容: 根据Java语言规范,无法将构造函数标记为已同步,因为其他线程在创建该对象的线程完成之前无法看到正在创建的对象。这似乎有些奇怪,因为在构造对象时,我确实可以让另一个线程查看该对象: 我知道这是一个非常人为的示例,但从理论上讲,似乎有人可以提出一个更现实的案例,在该案例中,标记构造函数为同步状态是合法的,以防止此类线程的竞争。 我的问题是:Java是否有理由特别禁止在构造函数上使用syn
我刚刚开始用Java编程。在讨论方法和构造函数时,我们使用的文本是缺乏的。我不确定方法或构造函数到底是什么,也不确定是什么让它们独一无二。有人能帮我定义它们并区分两者吗?