【问题标题】:Singleton Object in Java Web serviceJava Web 服务中的单例对象
【发布时间】:2012-06-21 05:13:09
【问题描述】:

早上好, 我目前正在开发一个公开 Web 服务接口的 Java Web 应用程序。为了将全局对象保存在内存中,我将以下类用作 Singleton:

public class SingletonMap {
    private static final SingletonMap instance = new SingletonMap();
    private static HashMap couponMap = null;
    private static long creationTime;

    private SingletonMap() {
        creationTime = System.currentTimeMillis();
        couponMap = new HashMap();
    }

    public static synchronized SingletonMap getInstance() {
        return instance;
    }

    public static long getCreationTime() {
        return creationTime;
    }
}

我正在使用上述类,以便为 Web 服务的所有线程提供相同的 HashMap 实例。维护 SingletonMap 对象的 Web 服务类如下:

@WebService()
public class ETL_WS {
    private String TOMCAT_TEMP_DIR;
    private final int BUFFER_SIZE = 10000000;
    private static SingletonMap couponMap;
    private static SingletonProductMap productCategoryMap;
    private String dbTable = "user_preferences";

    public ETL_WS() {
        Context context = null;
        try {
            context = (Context) new InitialContext().lookup("java:comp/env");
            this.TOMCAT_TEMP_DIR = (String) context.lookup("FILE_UPLOAD_TEMP_DIR");
        }catch(NamingException e) {
        System.err.println(e.getMessage());
    }

    public long getCouponMapCreationTime() {
        return couponMap.getCreationTime();
    }

}

我使用 getCouponMapCreationTime() 方法的原因是检查 Web 服务的所有线程是否都在访问同一个对象。上述方法是否正确?性能开销如何?你认为我需要 Singleton 属性,还是我可以只为所有线程使用静态 HashMap?如果我使用静态 HashMap,如果没有线程处于活动状态,它是否会被垃圾收集?

感谢您的宝贵时间。

【问题讨论】:

    标签: java singleton jax-ws


    【解决方案1】:

    JAX-WS Web 服务本身就是一个单例。这意味着所有请求都将使用单个 Web 服务实例(如 Servlet)来处理。

    因此,该类的任何成员都将在所有请求之间“共享”。在您的情况下,您不需要使您的成员(即 couponMap)成为静态属性。

    结论:别担心,你所有的线程(请求)都将访问同一个“couponMap”。因为您不再需要 getCouponMapCreationTime,所以我认为您可以消除 SingletonMap 抽象并直接在您的 Web 服务类中使用 Map。

    但我有一些非常重要的事情要补充。如果多个线程(请求)将访问您的地图,您必须使其成为线程安全的!!!有很多方法可以做到这一点,但我会给出一个想法:使用ConcurrentHashMap 而不是HashMap。这将使您的所有get(), put(), remove() 操作线程安全!如果您需要更大的范围,您可以使用同步块,但请避免同步方法,因为勺子太大并且总是在this 对象上同步。

    【讨论】:

    • 我明白了。如果客户端请求之间有很大的停顿,对象是否会被垃圾回收呢?我的意思是,如果 Web 服务空闲了一段时间,JVM 会运行垃圾收集器并清理我的实例吗?对不起,如果我很烦人,但我是这个领域的新手,而且我以前从未部署过具有持久内存 (RAM) 对象的 Web 服务。
    • 不,该对象永远不会被垃圾回收,因为框架保留了对它的引用。这类框架(servlet、jaxws 等)始终保留服务对象的一个​​实例,但它们实际创建/销毁的是线程(使用线程池策略)。不过不用担心,这不会影响你的内存共享数据!!!
    • 谢谢你ggarciao。您的快速回答对我帮助很大。
    • 很抱歉再次打扰您,但我尝试声明私有 ConcurrentHashMap couponMap; (甚至是静态的),但似乎只要客户端得到响应,对象就会死掉。
    • 我不相信@WebService 实例是单例的。或者,至少,并不是按照规范它必须是正确的。至少在一台 JEE 服务器上,这是不正确的。事实上,这似乎暗示 JAX-WS 服务的规范不是单例:stackoverflow.com/a/7010266/796761
    【解决方案2】:

    JAX-WS 有自己的模式来创建单例,您不需要使用静态字段。您在每个服务中使用 @Inject 注释。见这篇博文:http://weblogs.java.net/blog/jitu/archive/2010/02/19/jax-ws-cdi-java-ee-6-0(但不要使用@SessionScoped,使用@Singleton)

    其他几点:

    1. HashMap 不是线程安全的,您需要ConcurrentHashMap。

    2. 这个catch(NamingException e) { System.err.println(e.getMessage()); 没有帮助。将其重新抛出为RuntimeException。你无法从中恢复过来。

    3. 在这个阶段不要担心性能开销。一旦你有什么工作,测量它。

    【讨论】:

    • 感谢您的快速回答。我检查了您发布的链接,但确定所有线程都将使用我的 SingletonMap 类的相同实例吗?事实上,我有兴趣使用的 SingletonMap 对象应该被初始化一次(惰性),由所有 Web 服务线程使用,并且只有在 Web 服务出现故障时才被销毁。 P.S.:谢谢你的积分:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-19
    • 2010-09-16
    • 1970-01-01
    相关资源
    最近更新 更多