2017-09-08 4 views
0

長時間実行するクエリを実行するコントローラに新しいスレッドを作成しようとしています(listFromService = getListFromService();)。 今のところ、私はサービスに接続していません。 Thread.sleep(100000)を実行し、listFromServiceにダミーデータを入力して、このプロセスをシミュレートします。spring mvcコントローラのスレッドが機能しない

その後、このリストをCSVファイルに入れ、HttpServletResponseレスポンスに直接ストリームします。

このコードはスレッドなしで完全に動作しています。しかし、そのメインスレッドとユーザーをブロックすることは何もできません。

@RequestMapping(value = "/download") 
 
\t public void downloadCSV1(@RequestParam() final Map<String, String> params, 
 
\t \t \t HttpServletResponse response) throws IOException 
 
\t { 
 
\t 
 
\t \t new Thread() 
 
\t \t { 
 
\t \t  public void run() { 
 
\t \t   System.out.println("Before Running thread"); 
 
\t \t   List<Objects> listFromService; 
 
\t \t   try { 
 
\t \t \t \t \t Thread.sleep(10000); 
 
\t \t \t \t \t listFromService = getListFromService(); 
 
\t \t \t \t \t response.setHeader("Content-disposition", "attachment;filename="+ "metrics.csv"); 
 
\t \t \t \t \t ServletOutputStream outputStream; 
 
\t \t \t \t \t try { 
 
\t \t \t \t \t \t outputStream = response.getOutputStream(); 
 
\t \t \t \t \t \t listFromService.stream().forEach(item -> { 
 
\t \t \t \t \t \t \t try { 
 
\t \t \t \t \t \t \t \t processMetricsDownloadListItem(item, outputStream); 
 
\t \t \t \t \t \t \t } catch (IOException e) { 
 

 
\t \t \t \t \t \t \t \t e.printStackTrace(); 
 
\t \t \t \t \t \t \t } 
 
\t \t \t \t \t \t }); 
 
\t \t \t \t \t \t outputStream.flush(); 
 
\t \t \t \t \t } catch (IOException e1) { 
 
\t \t \t \t \t \t e1.printStackTrace(); 
 
\t \t \t \t \t } \t 
 
\t \t \t \t \t 
 
\t \t \t \t \t 
 
\t \t \t \t } catch (InterruptedException e) { 
 
     e.printStackTrace(); 
 
\t \t \t \t }  
 
\t \t } // end or run() 
 
\t \t }.start(); 
 
\t 
 
\t \t 
 

 
\t \t 
 
\t }

私は取得していますエラーは以下の通りです:

Exception in thread "Thread-5" java.lang.NullPointerException 
 
[tomcat:launchProperties] \t at org.apache.coyote.http11.InternalNioOutputBuffer.flushBuffer(InternalNioOutputBuffer.java:235) 
 
[tomcat:launchProperties] \t at org.apache.coyote.http11.InternalNioOutputBuffer.addToBB(InternalNioOutputBuffer.java:190) 
 
[tomcat:launchProperties] \t at org.apache.coyote.http11.InternalNioOutputBuffer.commit(InternalNioOutputBuffer.java:178) 
 
[tomcat:launchProperties] \t at org.apache.coyote.http11.AbstractHttp11Processor.action(AbstractHttp11Processor.java:750) 
 
[tomcat:launchProperties] \t at org.apache.coyote.Response.action(Response.java:177) 
 
[tomcat:launchProperties] \t at org.apache.coyote.http11.AbstractOutputBuffer.doWrite(AbstractOutputBuffer.java:249) 
 
.........

+0

おそらく役立つ:http://carlmartensen.com/completablefuture-deferredresult-async –

答えて

1

HTTPメソッドの呼び出しは、(例えばTomcatの)サーブレットコンテナを行う場合は作成します指定された要求に対応するための専用スレッド。このスレッドはいくつかのアクションを実行し、そのうちの1つはコントローラメソッド内のロジックを呼び出しています。あなたの場合は、別のスレッドを開始するだけです。その後、コンテナスレッドはライフサイクルを継続し、クライアントに応答を返し、最後にHttpServletResponseを閉じます。これはアプリケーションスレッドと同時に実行されます。したがって、アプリケーションのトレッドが起動し、コンテナスレッドによって既に閉じられているOutputStreamをフラッシュしようとすると、エラーが発生します。 start()の後にt.join()を追加すると、コードは別のスレッドなしで同じように動作します。

残念ながら、クライアントがサーバーからの応答を受け取った後にHTTP接続を再利用することはできないため、クライアント接続を解放し、後で計算結果をアプリケーションサーバーのみを使用して送信することはできません。クライアント側(例:AJAX)で非同期ツールを使用してサーバーへの非同期呼び出しを行い、結果が準備完了になったらアクションを実行する必要があります。サーバーへの呼び出しは常にブロックされますが、この場合は非同期クライアントスレッドがブロックされ、メインアプリケーションスレッドは引き続きユーザーの処理を処理します。

関連する問題