Java 实例化非最终静态变量是线程安全的吗?

Java 实例化非最终静态变量是线程安全的吗?,java,multithreading,design-patterns,thread-safety,jvm,Java,Multithreading,Design Patterns,Thread Safety,Jvm,这两个班是一样的吗 public class SingleTone { // yes this is a bug what if i change the class this way // private static SingleTone instance = new SingleTone(); // and empty constructor? private static SingleTone instance; private Single

这两个班是一样的吗

public class SingleTone {

    // yes this is a bug what if i change the class this way
    //  private static SingleTone instance = new SingleTone();
    // and empty constructor?
    private static SingleTone instance; 
    private SingleTone() {
        instance = new SingleTone();
    }

    public static SingleTone getInstance(){
        return instance;
    }
} 

构造函数实例化的非最终变量是否存在线程安全问题

问题2:

它们之间有什么区别

    private final static SingleTone instance = new SingleTone();

    private SingleTone() {
    }
这是:

    private final static SingleTone instance;

    private SingleTone() {
        instance = new SingleTone();
    }

魁斯顿1号

你的第一个例子不起作用

就像在创建该类型的对象之前调用SingleTone.getInstance()一样,它将返回null

第二个例子很好

问题2

同样的情况,您正在构造函数中设置一个静态字段。这没有意义,因为您不能保证在访问静态字段之前调用了构造函数

您可以这样做:

private final static SingleTone instance;

static {
    instance = new SingleTone();
}
这将在第一次加载类时实例化静态字段


回答你的评论

如果您这样做:

private static final SingleTone instance = new SingleTone();
这是线程安全的,就像第一个线程尚未完成初始化类,而另一个线程试图访问它,而另一个线程将阻止它一样


有关更多信息,请参见此问题:

这两个选项实际上是相同的(但在这两种情况下都缺少
super()
调用构造函数)

然而,使用私有静态字段实现singleton is Java往往不受欢迎。现在,我将使用枚举

public enum Elvis {
    INSTANCE;
    private final String[] favoriteSongs =
        { "Hound Dog", "Heartbreak Hotel" };

    public void printFavorites() {
        System.out.println(Arrays.toString(favoriteSongs));
    }
}

若你们想进一步阅读:

SingleTone类必须返回一个引用,所以第一个例子是完全错误的

考虑以下过程: 1.类加载由JVM启动 2.类被加载到JVM中。 3.构造函数执行 4.对象创建已完成

公共类单音{ 对于此示例,实例将在1和2之间处于活动状态 私有最终静态单音实例=新单音()

}

公共类单音{ 对于这个示例,实例将在3到4之间处于活动状态 私有最终静态单音实例

private SingleTone() {
    instance = new SingleTone();
}

public static SingleTone getInstance(){
    return instance;
}

}

是的,你说得对,如果我用private static SingleTone instance=new SingleTone()的方式重写我的第一个示例会怎么样;并删除构造函数实例!使用final有什么好处!(我正在寻找线程安全问题而不是性能)根据您的评论更新答案谢谢我得到了错误!然而,在我的评论中,我没有使用最终变量,也没有使用最终变量。我更新了答案,请再看一遍,我不确定我是否理解,但是如果您通过私有构造函数限制对字段的访问,并且不提供任何设置字段,那么您就不需要final。ie使用final不会使它更安全,更需要澄清:如果我用private static SingleTone instance=new SingleTone()的方式重写我的第一个示例;并删除构造函数实例!使用final有什么好处!(我寻求的是线程安全问题,而不是性能问题)问题原始版本的两部分都包含bug。而你的“澄清”问题现在是如此混乱,以至于无法回答。。。IMO.可以回答的一点是:有或没有
final
字段实际上是final,因为它保证只分配一次。它是线程安全的,因为赋值发生在类初始化时。我没有注意到问题中的错误。谢谢@cowls,我得到了部分答案,但是我仍然不知道使用静态非最终变量时的线程安全问题。我更新了我的问题,并尽我最大的努力来澄清它。我没有要求实现单音,我知道Enum的方式。
private SingleTone() {
}

public static SingleTone getInstance(){
    return instance;
}
private SingleTone() {
    instance = new SingleTone();
}

public static SingleTone getInstance(){
    return instance;
}