我想知道这段代码是否正确。当我在构造对象本身时将可运行对象提交给执行器服务时,这不会导致问题吗?
public class A implements Runnable {
public A() {
Executors.newSingleThreadExecutor().execute(this);
// some other initializations
}
}
当我们尝试在完全创建对象之前将对象提交给执行者时,这会导致任何问题吗?如果在所有初始化完成之前调用 run() 方法(如果可能的话),尚未初始化的变量是否仍为 null?
请不要要求我提出完整的代码,因为我一直在问这个问题,这是一个需要澄清的一般问题。
是的,可能存在问题。Executor
可能会读取您在构造函数中设置的字段,甚至在执行构造函数中的相应代码之前。通常,不应从构造函数内部公开this
。Java在构造函数完成后为对象提供了有用的保证,但是为了从中受益,您必须等待new X(...)
的结果才能使用它。
当我们尝试将对象提交给时,这会导致任何问题吗 甚至在完全创建它之前执行者?
首先,您可以获得仍在更改值final
变量 - 根据final
的语义,这是非常糟糕的。它可能导致多线程代码中出现非常难以跟踪的并发错误。
这段代码通常会打印几个零,甚至偶尔会打印4
,即使最终字段a
只被分配了4
值,并且除了4
之外,永远不应该看到任何其他值。
public class A implements Runnable {
private static ExecutorService threads = Executors.newSingleThreadExecutor();
final int a;
public A() {
threads.execute(this);
Thread.yield();
a = 4;
}
@Override
public void run() {
if (a != 4) {
System.out.println(a);
}
}
public static void main(String[] args) {
for (int i = 0; i < 50_000; i++) {
new A();
}
threads.shutdown();
}
}
如果在所有初始化完成之前调用 run() 方法 (如果可能的话),变量是否仍然为空,这些变量是 尚未初始化?
是的,尚未初始化的那些将null
用于引用变量,或默认值(0, false, ' ', 0d, 0f
等)用于基元类型。根据具有long
和double
字段的规范,甚至可以仅看到32位中的64位初始化(尽管在64位架构上,您不太可能观察到这一点)
几乎肯定会有问题。 您拥有的称为"此转义",您将 ctor 中的this
引用传递给外部方法。 这非常糟糕,对象在这一点上构造不完整,任何事情都可能发生。
您可能应该做的是将构造函数设为私有,并使用工厂方法来获取新实例并执行它(如果这是目标)。
public class A implements Runnable {
public A getNew() {
A a = new A();
Executors.newSingleThreadExecutor().execute(a);
return a;
}
private A() {
// some other initializations
}
}