【问题标题】:Creating thread for background task servlet为后台任务servlet创建线程
【发布时间】:2015-09-02 14:19:46
【问题描述】:

我的问题场景是:
在我的 servlet 中,我从某个地方(不相关)获得大量数据。我必须遍历所有这些数据并将其放入一个数组中,将其转换为 JSON 对象并将其发送到客户端进行查看。如果我在单个响应中执行此操作,则显示结果需要很长时间。因此,我需要做多线程。

创建的线程需要不断地将数据添加到列表中,而主线程在收到请求时(对数据的请求会定期发送)发送当前可用的列表。

例如,在第一次请求时,发送的响应是:1 2 3 第二个请求:4 5 6 等等。

现在我来解决实际问题:我不知道如何在 servlet 中进行多线程。我浏览了许多资源和示例,但这只会让我更加困惑。有些示例在 doGet 中创建了线程,我认为这是非常错误的,有些示例在 init() 方法中创建了它们,但我不知道如何传递参数并从线程中获取结果,如果它在 init 方法中声明(它不能是全局变量)。然后是 servletContextListener 的例子,但我没有发现任何有用或有意义的东西。

谁能给我一个可靠的来源,或者给我一些伪代码来解决我的问题。如果答案与上述场景相关,那将非常有帮助。

谢谢

【问题讨论】:

  • 请解释一下,一旦向您的servlet发出请求,您应该去请求数据(从servlet到外部数据)?还是 servlet 应该做一些关于获取数据的背景知识并为客户做好准备?
  • 为简单起见,数据已经存在。现在后台线程需要开始将该数据放入列表中(它可以在请求到来之前开始这样做)。当请求到来时,doGet 只是简单地以列表的当前状态进行响应。后台线程一直在向列表中添加数据。另一个请求来了,新列表被发送等等。
  • 如果它有助于从先前的请求中检索数据。我将该数据存储在 servlet 上下文中。现在,我要创建的线程正在将数据更改为列表

标签: java multithreading servlets


【解决方案1】:

创建的线程需要不断地向列表中添加数据,而 每当收到请求时主线程(对数据的请求继续 定期来)发送当前可用的列表。

如果我没听错的话,您希望获取一些数据作为后台服务,并在客户请求时为他们准备好(听起来像是在收集数据)。

嗯,在网络应用程序中创建线程,或者通常托管环境附带的东西是不同的,隐式创建线程会导致内存泄漏。

一个好的解决方案是使用ThreadPool(通过容器上下文/ndi 或手动创建)。
并且它必须以可管理的方式创建,您可以通过与环境相关的事件来控制它。

ContextListener 是你的朋友,有一个上下文监听器类,像这样。

public class dear_daemon implements ServletContextListener,Runnable{
ExecutorService the_pool;
Thread the_evil;
/*following get invoked once the context is called*/
public void contextInitialized(ServletContextEvent sce){
/*initialize the thread-pool, and run evil thread*/}
/*following get invoked once the context is destroying*/
public void contextDestroyed(ServletContextEvent sce){eviling=false;
/*stop evil(this) thread(first), then destroy thread pool*/
}
volatile boolean eviling=true;
public void run(){
 while(eviling){
  /*run Runnable instance which do data fetching using thread-pool*/
 }
}
}

并在web.xml注册监听器

<listener>
    <listener-class>dudes.dear_daemon</listener-class>
</listener>

有一个类(runnable) 进行数据获取,并通过邪恶线程调用它,每个实例使用一个线程。

ContextLisstener 帮助您正确关闭和管理容器的 init 和 hult 事件,使用与 servlet init 相同的东西是可能的,但请确保您对 servlet 的 destroy 方法执行相同的操作。

如果你喜欢用线程来处理它,请确保你做的事情是线程安全的,因为你有一个东西来存储数据(一个列表)。

如果需要任何同步(例如对获取的数据进行排序),请确保您操作正确,否则您将面临死锁或低性能代码。

如果需要任何(可能)IO 操作来获取数据,请注意 java IO 是阻塞的,因此设置赞赏的读取和连接超时,或者如果您可以处理复杂的 NIO 东西,则切换到 NIO。

如果应用这些更改会使环境变得复杂,并且您喜欢做其他解决方案,您可以简单地从 web-profile 提取数据并将其作为外部守护程序服务或应用程序运行,其中应用程序将通过获取的使用调用您的 CGI/Servlet 之一将数据传输到服务器上下文。

【讨论】:

  • 很抱歉,我仍有困惑。据我所知,servletcontextlistener 用于在 Web 应用程序启动之前执行代码。如何将 doGet() 中的数据表传递给它?据我所知,这需要事先将数据存储在某个地方。 (我想你误解了上述数据的存在......在Web应用程序启动后通过ajax请求接收数据。收到这些数据后,我希望整个多线程和数据列表转换发生)
  • @FurqanTariq 每个请求都带有一个(可能是新的)servlet 线程,所以如果你得到 100 个异步 ajax 调用,你将得到 100 个异步 servlet 调用,每个调用都会运行(调用)由一个线程。除非您将上下文的(默认)多线程设置为单线程。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-09-02
  • 1970-01-01
  • 2020-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多