0

我正在开发一个现有的基于 Web 的应用程序,它使用静态地图来存储特定于 Application 的数据。

这是我下面的代码,它负责将数据存储在 aConcurrentHashMap中,如下所示。

public class MyClass 

    // Class variable
    private static Map<String, UserThread> usermap = new ConcurrentHashMap<String, UserThread>();  

// Inside a Method 
public void userData()
 {
 UserThread  userThread= usermap.get(getLoginId());
 if (userThread == null) {
 userThread = new UserThread();
 userThread.start();
 usermap.put(getLoginId(), userThread);
 }
}

应用程序运行良好,我的问题是,这是一个有效的代码,因为我们可以将数据存储在静态变量中吗?(这里的静态ConcurrentHashMap包含特定于应用程序的数据)

4

4 回答 4

2

应避免使用任何类型的静态变量和缓存,尤其是在 Web 应用程序等多线程环境中。您的代码有几个问题:

  1. 您是否从地图中删除了 UserThreads?你怎么知道什么时候应该删除它们?如果客户端的浏览器崩溃了怎么办?如果您不删除它们,您将在应用程序运行一段时间后询问内存不足错误。
  2. 以您使用它的方式使用 ConcurrentHashMap 不是线程安全的,因为另一个线程可能会在if (userThread == null) 和之间添加一个 UserThread usermap.put(getLoginId(), userThread);。HashMap 的并发版本并没有像看起来那样神奇地解决所有线程安全问题。
  3. 在 servlet 容器中生成自己的线程并不是一个好主意。有更好的方法来执行后台任务,但首先你需要说明线程正在尝试做什么。

在任何类型的应用程序中,通常使用任何类型的此类静态缓存都是坏主意。在您的情况下,将特定于应用程序的数据保留在用户会话中会更好。

于 2012-09-24T10:29:07.243 回答
1

使用静态映射,除非您确定添加到映射中的每个条目的生命周期,即谁将添加它们,条目将在那里停留多长时间以及何时将它们删除,否则您将面临内存泄漏的风险可以在 GC 期间声明它们。否则,您的应用程序将耗尽内存并开始抛出 OOME。

于 2012-09-24T10:24:28.057 回答
0

在这种情况下,将在一台机器上登录的用户将拥有与在第二台机器上相同的会话。我敢打赌这不是一个好方法。

前段时间我问过Semi static field in Java application,Alessandro Santini 给了我非常好的解决方案ThreadLocal。看一下这个。

于 2012-09-24T10:22:56.200 回答
0
  1. AFAIK 根据规范不能在容器内启动自己的线程。您应该为此使用 WorkManager。但我所知道的唯一执行该规则的服务器是 Websphere 应用程序服务器。

  2. 原则上静态变量是可以的,当然,如果您在集群环境中运行,每个服务器都会有自己的静态变量实例。这可能是也可能不是问题。

所以从技术上讲,你可能没问题。

另一方面,我真的很好奇你想用所有这些线程实现什么。如果您为每个用户启动一个线程,这是 DOS 攻击的绝佳攻击媒介。我也不知道你为什么想做这样的事情。

于 2012-09-24T10:31:43.603 回答