好的或坏的想法:使用Java的多用户基于servlet的Web应用程序中的多个线程

时间:2011-07-01 13:00:23

标签: java multithreading

我目前正在构建一个基于java-servlet的Web应用程序,该应用程序应该为很多用户提供服务(不要问我“有多少”:-) - 我还不知道)

但是,在使用应用程序时,可能会在服务器端进行一些长时间处理。 为了避免糟糕的UI响应,我决定将这些处理操作移到自己的线程中。 这意味着一旦用户登录,就会发生1-10个线程在后台运行(每个用户!)。

我曾经听说在Web应用程序中使用多个线程是一个“坏主意”。

这是真的,如果是的话:为什么?

更新:我忘了提到我的应用程序严重依赖于ajax调用。每个用户操作都会导致新的ajax调用。因此,当主servlet线程忙时,ajax调用需要很长时间才能处理。这就是我想使用多线程的原因。

5 个答案:

答案 0 :(得分:5)

自己手动创建线程是个坏主意。这已经在SO中进行了很多讨论。例如,请参阅this问题。

另一个question讨论了替代解决方案。

答案 1 :(得分:2)

“坏主意”不是多线程。 Java EE最初编写,因此多线程掌握在app服务器手中,因此不鼓励用户启动自己的线程。

我认为您真正想要的是长时间运行任务的异步处理,因此用户无需等待它们继续完成。

您可以使用JMS执行此操作,并保持在Java EE着色书中。我认为现在自己做更安全,因为java.util.concurrent包中有新的类和结构。

这仍然不是一件容易的事。多线程代码并非易事。但我认为它比以前在Java中更容易。

部分问题可能是你要求servlet做得太多。 Servlet应该监听HTTP请求并协调从其他类获取响应,而不是自己进行所有处理。也许你的servlet告诉你是时候重构了一下。这将有助于您的测试,因为您将能够在不运行servlet / JSP引擎的情况下对这些异步类进行单元测试。

通过HTTP调用服务不需要阻止。如果服务可以返回一个令牌,即FedEx,告诉应用程序何时以及如何获得响应,则没有理由说服务无法异步处理。这是您应该从客户端隐藏的服务的实现细节。

答案 2 :(得分:1)

1。
很棒的主意。
这并不常见,但没有错 如果您认为需要异步任务以获得更好的用户体验。只需使用它。

2。
你需要小心。
2.1。
创建和销毁线程会给服务器增加很多开销 您最好使用执行程序,例如java.util.concurrent.ThreadPoolExecutor

2.2。
不要只使用Executors.newFixedThreadPool()。这是为初学者和隐藏危险的细节 您需要知道ThreadPoolExecutor的边缘行为,并正确配置它。

  • 您的任务有多少线程足够?你需要计算出来。
  • 如果游泳池中没有免费游戏,会发生什么?不同的配置可以使其等待,缓存或放弃新任务。你应该期待什么?
  • 如果任务运行时间太长(例如无限循环)会发生什么? java中没有真正的超时和退出机制。你怎么防止这些。

答案 3 :(得分:0)

如果应用程序需要它,那么我说继续执行后台线程,但是,由于您不知道您将拥有多少用户,因此您承担的风险很大,您将使您的服务器瘫痪。如果它们适用于您的情况,您可以考虑一些替代方案。您可以完全脱机运行后台任务,例如在批量工作?你能限制每个登录用户需要的线程数吗?如何将后台线程的结果返回给用户?

答案 4 :(得分:0)

这主要有三个主要原因:

  1. 过多的运行线程可能会导致系统资源中断并导致一些奇怪的事情,例如饥饿和优先级倒置。通常可以使用thread pool解决此问题。
  2. 用户会话持续时间不可预测。用户可以发起动作并去喝咖啡,或者他/她可能会抱怨延迟重做动作。这可能导致创建多个后台作业,因此需要复杂的控制,当我们谈论线程时,我们永远不会确定我们是否没有离开竞争条件或未解决的情况。
  3. 最有可能的servlet会与线程进行一些交互。现在假设你的应用程序需要扩展,所以你使用一个集群容器(毕竟,你有“很多”用户)。容器可以钝化会话并在另一个节点中恢复它。但是您的线程将保留在初始节点中,因此会话和线程之间的链接将被破坏。这结束于意外的异常和错误500 - 服务器故障。
  4. 我认为最好的解决方案是设计你的应用程序,这样它就不会创建那么多的后台线程。

    但是如果你坚持或真的需要它,请尝试使用Java EE message driven beans(MDB)并让你的servlet使用JMS调用它,就像@duffymo所说的那样。

    挑战在于如何在MDB和用户会话之间进行通信。也许你的servlet可以创建一个JMS queuetopic并将它发送给MDB以供他们回复,但我不知道JMS连接的servlet端是否可以被钝化和恢复。

    另一种形式的通信是JNDI或外部数据库或文件,但这需要轮询,这可能没有响应或CPU过多。