Java中线程安全单例的工厂

时间:2011-05-22 13:22:28

标签: java multithreading singleton factory

这是我一直用于Factory的基本模式的示例,它返回一个线程安全的Singleton:

public class UserServiceFactory {

    private volatile static UserService userService;

    private UserServiceFactory() { }

    public static UserService getInstance() {
        if (userService == null) {
            synchronized(UserServiceImpl.class) {            
                if (userService == null) {
                    userService = new UserServiceImpl();
                }        
            }
        }

        return userService;
    }

}

它使用volatile和double check惯用法来确保创建单个实例并在线程中可见。

在1.6 +中实现相同目标是否有更简洁和/或更便宜的方式。

3 个答案:

答案 0 :(得分:19)

使用Initialization On Demand Holder成语,它更简单,更易读:

public class UserServiceFactory {

    private UserServiceFactory () {}

    private static class UserServiceHolder {
        private static final UserService INSTANCE = new UserService();
    }

    public static UserService getInstance() {
        return UserServiceHolder.INSTANCE;
    }

}

但是,我更喜欢Just Create One成语。


更新:正如您的问题历史记录所确认的那样,您正在使用Java EE。如果您的容器支持它,您也可以使它成为@Singleton EJB并使用@EJB来注入它(尽管@Stateless更可取,因为@Singleton默认是读取锁定的) 。

@Singleton
public class UserService {}

例如在JSF托管bean中

@EJB
private UserService userService;

这样您就可以将实例化作业委派给容器。

答案 1 :(得分:3)

您可以让类加载器执行其maigc并在启动时初始化静态变量 - 这可以保证正常工作,因为类加载器可以保证单线程行为。

如果你想懒惰地初始化实例并且大多数是无锁的,那么不,你必须这样做,并确保你使用Java> = 1.5

编辑:请参阅BalusC的解决方案,该解决方案更智能地使用类加载器。请注意,这一切都有效,因为类加载器懒惰地初始化类 - 即它们仅在第一次访问时加载 - 并且因为内部类在这方面就像普通类一样处理(仅仅因为加载外部类并不意味着内部类)加载了类)

答案 2 :(得分:0)

为什么不

public synchronized static UserService getInstance() {
    if (userService == null) {
        userService = new UserServiceImpl();    
    }
    return userService;
}