在java中注入/访问线程安全单例的最佳方法

在java中注入/访问线程安全单例的最佳方法,java,multithreading,singleton,Java,Multithreading,Singleton,我对这段代码完全感到困惑,因为我知道它的目的是让线程安全地访问对象数据服务的单个实例,但我不知道它是否实现了这一点 这对我来说很突出 调用方类: protected final DataService dataService = DataService.getInstance(); 单例类方法: private static DataService dService=null; public static synchronized DataService getInstance() {

我对这段代码完全感到困惑,因为我知道它的目的是让线程安全地访问对象数据服务的单个实例,但我不知道它是否实现了这一点

这对我来说很突出 调用方类:

protected final DataService dataService = DataService.getInstance();
单例类方法:

private static DataService dService=null;
public static synchronized DataService getInstance() {
    if (dService == null)
        dService = new DataService();
    return dService;
}
在调用类中使用受保护的最终修饰符可以实现什么


它们是必要的还是良好的实践?

第一行中的受保护和最终修饰符对您所指的单例性质没有任何贡献

Protected只是访问修饰符,final决定是否可以重新分配变量


真正让它成为单例的是,您只创建了一个dService对象(通过
newdataservice()
)由于该方法是同步的,您可以保证不会同时调用该方法,这可能会导致错误地创建两个单独的对象。

因此我最终自己挖掘了

我发现这样做的一个低效的方式是单身被称为

在软件工程中,双重检查锁定(也称为“双重检查锁定优化”)是一种软件设计模式,用于通过首先测试锁定标准(“锁定提示”)来减少获取锁定的开销没有实际获取锁。只有当锁定标准检查表明需要锁定时,实际的锁定逻辑才会继续。 " " 因为在某些极端情况下,同步方法可能会使性能降低100倍或更高 "

这里提到的Java1.5+的最佳方法是使用volatile

class Foo {
    private volatile Helper helper;
    public Helper getHelper() {
        Helper result = helper;
        if (result == null) {
            synchronized(this) {
                result = helper;
                if (result == null) {
                    helper = result = new Helper();
                }
            }
        }
        return result;
    }

    // other functions and members...
}
volatile字段只被访问一次(由于“return result;”而不是“return helper;”),这可以将方法的总体性能提高25%

正如Brian Benzinger所说,受保护的和最终的修饰符对singleton类的线程安全没有帮助。Protected定义调用方类中字段的可见性,即该字段可以被包中的其他类访问。最后一个修饰符表示字段必须在实例化时明确分配,以后不能重新分配

虽然在Java中有许多实现singleton模式的方法,但这是我所知道的最好的实现:

class Foo {
    private static volatile Bar bar = null;
    public static Bar getBar() {
        if (bar == null) {
            synchronized(Foo.class) {
                if (bar == null)
                    bar = new Bar(); 
            }
        }
        return bar;
    }
}

最后一个修饰符是否会导致异常,这一点让我感到困惑。如果以某种方式将对象从null重新分配给object?有可能吗?
final DataService DataService
对象引用将只指向从
getInstance()
方法返回的内容。由于该方法总是检查以确保在返回对象引用之前实例化了
私有数据服务
对象,因此答案是否定的,您无法返回空指针。同样需要注意的是,在Java 1.5中,您可以使用枚举实现更简单的实现,但这并不适合所有情况。看见