【问题标题】:Does Singleton class with its instance as volatile make the instance data to be load again?实例为 volatile 的 Singleton 类是否会再次加载实例数据?
【发布时间】:2013-09-26 10:32:16
【问题描述】:

在我的应用程序中,Server 类在启动时加载,所有数据都缓存一次。

它是一个单例类,它的实例变量不是 volatile 即

private static Server server;

findbug分析后,我要改成volatile,(如下图

public class Server {
    private static volatile Server server;

    public static Server getInstance(){
        if(server == null){
            synchronized (Server .class) {
                if(server == null){
                    try {
                        server = new Server(....);
                    } catch (IOException e) {
                        Logger.logError(MODULE, "IO Error while creating server home location: " + strServerHome);
                        Logger.logTrace(MODULE, e);
                    }
                }
            }
        }
        return server;
    }.......
}

但是在阅读了关于 volatile on stack 的文章和 Q/A 之后,我认为 volatile 会使数据再次被加载,因为 volatile 会从内存中读取信息而不是缓存。

那么我应该让我的变量不可变吗?

如果不稳定,那么我是否必须再次加载我的数据?

【问题讨论】:

标签: java synchronization singleton volatile


【解决方案1】:

通常认为最安全的创建线程安全单例的方法是使其成为枚举...

 public enum Server{
      INSTANCE;

      public Server getInstance(){
          return INSTANCE;
      }

      private Server(){...}

      // rest of methods here
 }

Singleton:The Enum Way

【讨论】:

  • 但那不是偷懒,不是吗?
  • 第一次引用类时会加载。
【解决方案2】:

是的——如果没有volatile,你就会得到臭名昭著的“双重检查锁定”反模式,它不是线程安全的(即使看起来如此)。 (即使使用 volatile,它在 Java 5 之前的 Java 版本中也不是线程安全的)。

http://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java

但是虽然它的线程安全与volatile 和Java >=5,它的丑陋代码,所以你应该写一个简单的synchronized getInstance 方法...

public static synchronized Server getInstance() {
    if (server == null) server = new Servier(...);
    return server;
}

...或使用按需持有者模式的初始化器:

private static class ServerHolder {
    public static Server server = new Server(...);
}

public static Server getInstance() {
    return ServerHolder.server;
}

因为ServerHolder类在第一次使用时被延迟加载,所以在第一次调用getInstance时会发生类初始化,因此Server会被延迟实例化。

【讨论】:

  • 但是我是否必须再次加载我的数据,因为我不希望这样做。
  • 什么数据?我不明白。第一个示例与您的示例没有什么不同,只是它是线程安全的(并且更简单)。第二个只是一个优雅的变化。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-30
  • 1970-01-01
  • 2013-04-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多