1

我有一个 Web 应用程序,在单个请求中可能需要加载数百个数据。现在的问题是数据是分散的。所以,我必须从几个地方加载数据,对它们应用过滤器,处理它们然后做出响应。依次执行所有这些操作会使 servlet变慢

所以我想到了将所有数据加载到单独的线程中,例如t[i] = new Thread(loadData).start();,等待所有线程完成使用while(i < count) t[i].join();,完成后,加入数据并响应。

现在我不确定这种方法是否正确或有更好的方法。我在某处读到过,不建议在 servlet 中生成线程。

我想要的代码看起来像这样。

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 
{
       Iterable<?> requireddata = requiredData(request);
       Thread[] t = new Thread[requireddata.size];
       int i = 0;
       while (requireddata.hasNext())
       {
             t[i]  = new Thread(new loadData(requiredata.next())).start();
             i++;
       }
       for(i = 0 ; i < t.length ; i++)
         t[i].join();
       // after getting the data process and respond!
}
4

4 回答 4

6

主要问题是,如果您的 servlet 收到许多并发请求,您将使服务器瘫痪,因为您没有限制可以产生的线程数。另一个问题是你不断地创建新线程而不是重用它们,这是低效的。

使用线程池可以轻松解决这两个问题。Java 对它们有原生支持。阅读教程

此外,请确保在 webapp 关闭时使用 ServletContextListener 关闭线程池。

于 2013-02-09T10:54:00.853 回答
0

由于您正在等待所有线程完成然后提供响应,因此如果您仅使用 CPU 周期,IMO 多线程将无济于事。它只会通过在线程中添加上下文切换延迟来增加响应时间。单线程会更好。但是,如果涉及网络/ IO 等,您可以使用线程池。

但是您想重新考虑您的方法。不建议在 http 请求中同步处理大量数据。对最终用户来说不会是一个很好的体验。您可以做的是启动一个线程来处理数据并提供“正在处理”的响应。您可以随时为网络用户提供某种手势来检查状态。

于 2013-03-08T07:34:15.580 回答
0

您可以考虑使用 java.util.concurrent api 中的 Executor 框架。例如,您可以将计算任务创建为 Callable,然后将该任务提交给 ThreadPoolExecutor。Java Concurrency in Practice 中的示例代码:-

public class Renderer {
    private final ExecutorService executor;
    Renderer(ExecutorService executor) { this.executor = executor; }

    void renderPage(CharSequence source) {
        final List<ImageInfo> info = scanForImageInfo(source);
        CompletionService<ImageData> completionService =
            new ExecutorCompletionService<ImageData>(executor);
    for (final ImageInfo imageInfo : info)
        completionService.submit(new Callable<ImageData>() {
            public ImageData call() {
                return imageInfo.downloadImage();
                }
               });
renderText(source);
try {
    for (int t = 0, n = info.size(); t < n; t++) {
    Future<ImageData> f = completionService.take();
    ImageData imageData = f.get();
    renderImage(imageData);
    }
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
} catch (ExecutionException e) {
    throw launderThrowable(e.getCause());
}
  }
}
于 2013-02-09T11:01:52.127 回答
0

听起来像是CyclicBarrier的问题。

例如:

ExecutorService executor = Executors.newFixedThreadPool(requireddata.size);

public void executeAllAndAwaitCompletion(List<? extends T> threads){
   final CyclicBarrier barrier = new CyclicBarrier(threads.size() + 1);
   for(final T thread : threads){
       executor.submit(new Runnable(){
           public void run(){
                //it is not a mistake to call run() here
                thread.run();
                barrier.await();
           }
       }); 
    }
   barrier.await();
}

threads一旦所有其他线程完成,最后一个线程将被执行。

与其调用Executors.newFixedThreadPool(requireddata.size);,不如复用一些已有的线程池。

于 2013-02-09T11:18:28.327 回答