2013-02-09 116 views
1

我有一個web應用程序,在單個請求可能需要加載數百個數據。現在問題是數據是分散的。所以,我必須從幾個地方加載數據,在它們上應用過濾器,處理它們然後做出響應。依次執行所有這些操作使得servlet 變得緩慢在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! 
} 

回答

6

的主要問題是,你把服務器癱瘓,如果許多併發請求來爲你的servlet,因爲你不限制可以產生的線程數。另一個問題是你不斷重新創建新線程,而不是重用它們,效率不高。

這兩個問題很容易通過使用線程池解決。 Java對它們有本地支持。閱讀the tutorial

另外,請確保在webapp關閉時使用ServletContextListener關閉線程池。

0

您可以考慮使用java.util.concurrent api中的Executor框架。例如,您可以將計算任務創建爲Callable,然後將該任務提交給ThreadPoolExecutor。從Java併發示例代碼的實際應用: -

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()); 
} 
    } 
} 
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最後一個線程將被excuted。

而不是調用Executors.newFixedThreadPool(requireddata.size);,最好重用一些現有的線程池。

0

由於您正在等待所有線程完成,然後您提供了響應,所以如果您僅使用CPU週期,IMO多線程將無法提供幫助。它只會通過在線程中添加上下文切換延遲來增加響應時間。單線程會更好。但是如果涉及到網絡/ IO等,你可以利用線程池。

但是你想重新考慮你的方法。在http請求中同步處理大量數據不可取。對於最終用戶來說不是一個好的體驗。你可以做的是啓動一個線程來處理數據,並提供一個「正在處理」的響應。您可以向網絡用戶提供某種形式的手勢,以隨時檢查狀態。