这是Singleton的线程安全实现吗?

时间:2017-11-14 06:04:35

标签: java multithreading

我阅读了Wikipeida的Singleton介绍,并编写了这个Singleton类。可能有线程安全问题吗?

 public class Engine {

    private static volatile Engine instance = null;
    private final Pipeline pipeline;

    private Engine() {
        pipeline = createEngine(SystemProperties.LANGUAGE);

    }

    public static Engine getInstance() {
        if (instance == null) {
            synchronized (Engine.class) {
                if (instance == null) {
                    instance = new Engine();
                }
            }
        }
        return instance;
    }

    private Pipeline createEngine(Constants.Language langauge) {
        Pipeline pipeline;
        if (langauge == Constants.Language.Chinese) {
            Properties props = IOUtils.readProperties("properties/chinese.properties");
            pipeline = new Pipeline(props);
        } else if (langauge == Constants.Language.English) {
            Properties props = IOUtils.readProperties("properties/english.properties");
            pipeline = new Pipeline(props);
        } else {
            throw new IllegalStateException("Unknow langauge not supported!");
        }
        return pipeline;
    }
}

使用它的客户端代码:

    private List<String> segment(String str) {

            Engine ENGINE = Engine.getInstance();
            List<String> tokens = new ArrayList<>();
             ...
            try {
                ENGINE.annotate(tokens);
            }catch(Exception e){
                log.warn("can't annotate this sentence:" + str);
            }
            ...

            return tokens;
        }

2 个答案:

答案 0 :(得分:0)

YES。 全球: 创建线程安全的单例类的更简单方法是使全局访问方法同步 一次只能有一个线程执行此方法。 由于与同步方法相关的成本,它降低了性能。 为了避免每次额外的开销,使用双重检查锁定原则。 在这种方法中,synchronized块在if条件(如何使用)中使用,并进行额外的检查以确保只创建一个singleton类的实例。 另请注意,单身可以通过反射销毁。为了避免这个问题,Joshua Bloch建议使用Enum来实现Singleton设计模式。由于Java确保任何枚举值仅在Java程序中实例化一次。

public enum EnumSingleton {

INSTANCE;

public static void doSomething(){
    //do something
}

}

只是建议要完全理解单例模式,最好在GO4书中阅读,或者在第一版设计模式中阅读Joshua Bloch Effective Java第2版。有一章关于单身人士。

答案 1 :(得分:0)

Wikipedia article中所述,它在Java 5.0+中是线程安全的。

重要的是要知道volatile关键字实际上使其成为线程安全的。 Java允许其他线程使用部分构造的类,并且线程使用其他线程的变量的本地副本,这些变量组合在一起可能导致线程B继续使用线程A中尚未完全初始化的类的情况volatile关键字保证不会发生这种情况,但性能成本略有增加。

除了下面的简单(和完全线程安全)实现相比,这种延迟初始化方式过于复杂,它依赖于类加载的保证:

public enum Singleton {
  INSTANCE;

  private Singleton() {
    // initialization of Singleton
  }
}