Java 作为最终类构造函数的最后一条语句启动线程

Java 作为最终类构造函数的最后一条语句启动线程,java,multithreading,concurrency,Java,Multithreading,Concurrency,我理解这一点,因为它可能在完全建造之前就让它逃逸了。例如: public final class Test { private final int value; public Test(int value) throws InterruptedException { start(); this.value = value; } private void start() throws InterruptedException {

我理解这一点,因为它可能在完全建造之前就让它逃逸了。例如:

public final class Test {

    private final int value;

    public Test(int value) throws InterruptedException {
        start();
        this.value = value;
    }

    private void start() throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            new Thread(new Runnable() {

                @Override
                public void run() {
                    System.out.println("Construction OK = " + Boolean.toString(Test.this.value == 5));
                }
            }).start();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Test test = new Test(5);
    }
}
编辑

我不认为以前有人问过这个问题,因为这个问题比“我可以在构造函数中启动线程”更具体:线程在构造函数的最后一个语句中启动,这意味着对象构造已经完成(据我所知)在这个特殊的情况下,我会考虑标记<代码>值<代码>为<代码> Value(或使用),并在设置值后启动线程:

this.value = value;   // this.value.set(value)  if using AtomicBoolean
start();
如果使用这个稍微狡猾的解决方案,我也会使类
final
,以避免Andreas\D描述的问题


关于您的编辑:

[…]这意味着对象构造已经完成(据我所知)

这是正确的,但是考虑下面的场景:

您的测试线程稍微复杂一些,可以访问测试列表
testList
。现在如果你这样做了

testList.add(new Test());
在构造函数中启动的线程可能在列表中找不到关联的测试,因为它尚未添加。这样做是可以避免的

Test t = new Test();
testList.add(t);
t.start();
相关问题:


有,因为
Test
可以子类化,然后在创建实例之前执行
start()
。子类构造函数可能还有更多的工作要做


因此,类至少应该是final。

在调用start方法的构造函数中

start()
是班上最好的学生。现在您可以注意到您正在调用的方法是这个类的一个对象,它还没有被创建。因此,您仍在将未构造对象的引用传递给方法。您已经在对象的创建中包含了methodcall本身,而对象的任何方法都应该在对象完全构造之后调用

因此,仍然存在与之相关的风险。 这也是一个非常好的问题。

同步(新对象())不会阻止重新排序-因为监视器是一个局部变量,编译器实际上可以忽略同步块


特别是,编译器可以证明两个THRED不可能锁定在同一个监视器上(根据局部变量的定义),因此同步块是多余的,可以忽略。

可能是重复的(我错过了什么吗?人们今天的向下投票会得到代表分吗??)@波格丹·玛丽·桑,看我的edit@assylias,更新我的答案,在你添加的文本上加上一条评论。谢谢你的编辑-我正在努力理解它(我的大脑受伤了)!我认为问题是,这种风险是什么?我的对象的完整状态已初始化(在本例中只有一个变量),因此可能会出现什么问题?您的方法中可能有一些语句会导致对对象进行一些修改。
start()