我阅读了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;
}
答案 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
}
}