7

早上好,我目前正在开发一个公开 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,如果没有线程处于活动状态,它会被垃圾收集吗?

感谢您的时间。

4

2 回答 2

11

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

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

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

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

于 2012-06-19T07:52:10.023 回答
4

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. 在这个阶段不要担心性能开销。一旦你有东西工作,就测量它。

于 2012-06-19T07:47:07.220 回答