是否实例化非最终静态变量Thread-Safe?

时间:2013-03-18 12:08:23

标签: 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 SingleTone() {
        instance = new SingleTone();
    }

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

public class SingleTone {

    private final static SingleTone instance = new SingleTone();

    private 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();
    }

3 个答案:

答案 0 :(得分:2)

Queston 1

你的第一个例子不起作用。

如果在创建该类型的对象之前进行此调用SingleTone.getInstance(),它将返回null

第二个例子很好用

问题2

同样的情况,你在构造函数中实例化一个静态字段。这没有意义,因为你无法保证在访问静态字段之前已经调用了构造函数。

您可以这样做:

private final static SingleTone instance;

static {
    instance = new SingleTone();
}

这将在首次加载类时实例化静态字段。


回答你的评论。

如果你这样做:

private static final SingleTone instance = new SingleTone();

这是线程安全的,好像第一个线程没有完成初始化类而另一个线程试图访问它,另一个线程将阻塞。

有关详细信息,请参阅此问题:Thread safety of static blocks in Java

答案 1 :(得分:0)

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

但是,实现单例是使用私有静态字段的Java往往被弃用。现在,我会使用枚举。

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

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

如果您想进一步阅读:http://www.drdobbs.com/jvm/creating-and-destroying-java-objects-par/208403883?pgno=3

答案 2 :(得分:0)

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

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

public class SingleTone {     对于此示例,实例将在1和2之间存活     private final static SingleTone instance = new SingleTone();

private SingleTone() {
}

public static SingleTone getInstance(){
    return instance;
}

}

public class SingleTone {     对于此示例,实例将在3到4之间存活     private final static SingleTone实例;

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

public static SingleTone getInstance(){
    return instance;
}

}