首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Java中的构造函数同步

Java中的构造函数同步
EN

Stack Overflow用户
提问于 2012-09-27 06:23:32
回答 3查看 14.7K关注 0票数 23

有人告诉我,Java构造函数是同步的,所以在构造期间不能并发访问,我想知道:如果我有一个将对象存储在map中的构造函数,而另一个线程在其构造完成之前从该map检索对象,那么该线程是否会阻塞,直到构造函数完成?

让我用一些代码来演示:

代码语言:javascript
复制
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访问该对象并对其进行调用,它会阻塞吗?换句话说:

代码语言:javascript
复制
Test test = getTestById(someId);
test.doSomething(); // Does this line block until the constructor is done?

我只是想弄清楚构造函数同步在Java中走了多远,以及这样的代码是否会有问题。我最近看到这样的代码实现了这一点,而不是使用静态工厂方法,我想知道这在多线程系统中有多危险(或安全)。

EN

回答 3

Stack Overflow用户

发布于 2012-09-27 06:26:06

你被误导了。您所描述的内容实际上被称为不适当的发布,并在Java Concurrency in Practice一书中详细讨论。

所以,是的,另一个线程有可能获得对您的对象的引用,并在它完成初始化之前开始尝试使用它。但等等,更糟糕的是考虑一下这个答案:https://stackoverflow.com/a/2624784/122207 ...基本上,可以对引用赋值和构造函数完成进行重新排序。在引用的示例中,一个线程可以分配h = new Holder(i),另一个线程可以在新实例上调用h.assertSanity(),同时恰到好处地为在Holder的构造函数中分配的n成员获取两个不同的值。

票数 13
EN

Stack Overflow用户

发布于 2012-09-27 06:52:38

构造函数就像其他方法一样,没有额外的同步(除了处理final字段)。

如果稍后发布this,则代码可以正常工作

代码语言:javascript
复制
public Test() 
{
    // Some lengthy operation to fully initialize this object

    this.id = atomicIdGenerator.getAndIncrement();
    testsById.put(this.id, this);
}
票数 2
EN

Stack Overflow用户

发布于 2012-09-27 06:32:52

这不安全。在JVM中没有额外的同步。你可以这样做:

代码语言:javascript
复制
public class Test {
    private final Object lock = new Object();
    public Test() {
        synchronized (lock) {
            // your improper object reference publication
            // long initialization
        }
    }

    public void doSomething() {
        synchronized (lock) {
            // do something
        }
    }
}
票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12611366

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档