简体   繁体   English

关于实例变量初始化的线程安全性

[英]On the thread safety of instance variable initialization

I see this idiom of initializing instance variables quite a bit 我看到这个初始化实例变量的习惯很多

public class Test{
    private Long l = 1l;
    private MyClass mc = new MyClass();

    public Test(){}
    ...
 }

But I would prefer 但我更愿意

public class Test{
    private Long l;
    private MyClass mc;

    public Test(){
        l = 1l;
        mc = new MyClass();
    }
    ...
}

Considering that these are non-final variables, are the 2 approaches equivalent or is one "more" correct than the other in terms of thread safety? 考虑到这些是非最终变量,在线程安全方面,2种方法是等效的还是比另一种更“正确”?

Thread safety isn't an issue because this happens at construction phase, and two threads cannot be constructing the same object. 线程安全不是问题,因为这在构造阶段发生,并且两个线程不能构造相同的对象。 Well, if you let this escape from the constructor, it might be possible for another thread to access the object during construction, but you really shouldn't do that. 好吧,如果你让this从构造逃生,有可能另一个线程施工期间访问对象,但你真的不应该这样做。 Functionality-wise, the two options are the same, so even if there were thread-safety issues, they would affect both the same way. 功能方面,两个选项是相同的,所以即使存在线程安全问题,它们也会以同样的方式影响。

The first option, of initializing the fields at their declaration, is not always possible if you need to do some computation that cannot be done in an initializer (even then, you can keep the initialization out of the constructor if you do it in an initializer block, though). 如果你需要做一些无法在初始化程序中完成的计算,那么第一个选项是初始化声明中的字段并不总是可能的(即使这样,如果你在初始化程序中执行它,你可以保持初始化不在构造函数中)虽然阻止。 But if either way is possible, then it's purely a style issue, and I don't think there is a clear preference among Java programmers, so go with whichever seems better to you. 但是,如果任何一种方式都可行,那么它纯粹是一种风格问题,而且我认为Java程序员并不存在明显的偏好,所以请选择对你来说更好的方式。

They are both not thread-safe. 它们都不是线程安全的。 If thread A constructs the object, then thread B may or may not observer an incompletely initialized Test object or MyClass object. 如果线程A构造对象,则线程B可能会或可能不会观察到未完全初始化的Test对象或MyClass对象。 The visibility guarantees after a constructor exits only apply to final fields. 构造函数退出后的可见性保证仅适用于最终字段。

See http://pveentjer.wordpress.com/2007/03/18/immutability-doesnt-guarantee-thread-safety/ http://pveentjer.wordpress.com/2007/03/18/immutability-doesnt-guarantee-thread-safety/

since your variables are instance variables, not class variables, you don't have a thread safety issue during initialization using either method. 由于您的变量是实例变量,而不是类变量,因此在初始化期间使用任一方法都没有线程安全问题。 I'm sure others will chime in if there's a Java-standard-recommended best practice. 我敢肯定,如果有Java标准推荐的最佳实践,其他人也会参与进来。

I think it's the matter of personal preference and your project coding standards. 我认为这是个人偏好和项目编码标准的问题。

Just make sure you only initialize variables in one place ( either constructor, or inline ). 只需确保只在一个地方(构造函数或内联)初始化变量。

Having initialization work done in the constructor gives you a better place for exception handling. 在构造函数中完成初始化工作可以为您提供更好的异常处理空间。

In terms of thread safety, they are equivalent. 在线程安全方面,它们是等效的。 Both will need to execute the same instructions, and if you prefer the second (which I agree with you in your preference) then I would use that. 两者都需要执行相同的指令,如果您更喜欢第二个(我根据您的喜好与您达成一致),那么我会使用它。 If you want thread safety around a constructor, you would need a synchronized call around the constructor call. 如果您希望构造函数周围的线程安全,则需要围绕构造函数调用进行同步调用。

I am not sure if this was answered earlier. 我不确定这是否早些回答过。 But, I have a doubt on the following scenario: 但是,我对以下情况有疑问:

I am trying to create a @Component class where in, I have an instance variable. 我正在尝试创建一个@Component类,其中有一个实例变量。 Now, I want to create a new object of the instance variable for each request. 现在,我想为每个请求创建一个实例变量的新对象。 I am not sure which one is the right way to do it? 我不确定哪一个是正确的方法呢?

**Option 1:**
@Component
public class ClassA {

private ClassB classB = new ClassB();

public ClassB create(){
    return classB;
 }
}

**Option 2:**
@Component
public class ClassA {

private ClassB classB = null;

public ClassB create(){
    classB = new ClassB();
    return classB;
 }
}

**Option 3:**
@Component
public class ClassA {

public ClassB create(){
    ClassB classB = new ClassB();
    return classB;
 }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM