2013-05-22 71 views
2

我正在開發具有以下場景的多線程java sevlet 數據出現在不同的塊中,爲此我只需要在上次請求中發送響應。將數據塊轉發給其他類以保存數據。如何使用Listner發送Servlet響應

public class RequestController extends HttpServlet implements ResponseHandler { 
    private ExecutorService pool; 
    public static ConcurrentHashMap<String, HttpServletResponse> cache; 

    static { 
     cache = new ConcurrentHashMap<String, HttpServletResponse>(); 
    } 

protected void processRequest(HttpServletRequest request, HttpServletResponse response) 
      throws ServletException, IOException { 
     response.setContentType("text/html;charset=UTF-8"); 

     try { 


      BufferedReader br = request.getReader(); 
      String msg = br.readLine(); 
      br.close(); 

      if (msg == null) { 
       msg = request.getParameter("request"); 
       //return; 
      } 
      String number = msg.substring(msg.indexOf("//") + 2, msg.indexOf(";")); 
      System.out.println("number = " + number); 
      cache.put(number, response); 
      System.out.println("Request received"); 
      msg = URLDecoder.decode(msg, "UTF-8"); 
      System.out.println(msg); 
      pool.submit(new DuplicaterRequestHandler(msg, this)); 


     } catch (Exception e) { 
      e.printStackTrace(System.out); 
     } finally { 
     } 
    } 

}

這是我的servlet代碼。 緩存是我使用接收的所有請求後發送resonse靜態存儲

我有一個聽者,以及它告訴請求完成

public interface ResponseHandler { 

    public void sendResponse(String number, String data); 
} 

及其RequestController實現

的sevlet
@Override 
    public void sendResponse(String number, String data) { 

     System.out.print(number); 
     System.out.println(cache.containsKey(number)); 


     if (cache.containsKey(number)) { 
      try { 
       PrintWriter pr = cache.get(number).getWriter(); 
       pr.println(data); 
       pr.close(); 
       cache.remove(number); 
       System.out.println("response sent."); 
       System.out.println("data:" + data); 
      } catch (Exception e) { 
       e.printStackTrace(System.out); 
       System.out.println(e.getMessage()); 
      } 
     } 
    } 

一切看起來不錯,但它拋出一個例外,不是每一次,這是我不知道的。

java.lang.NullPointerException 
    at org.apache.coyote.http11.InternalOutputBuffer.realWriteBytes(InternalOutputBuffer.java:215) 
    at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:462) 
    at org.apache.tomcat.util.buf.ByteChunk.append(ByteChunk.java:366) 
    at org.apache.coyote.http11.InternalOutputBuffer$OutputStreamOutputBuffer.doWrite(InternalOutputBuffer.java:240) 
    at org.apache.coyote.http11.filters.ChunkedOutputFilter.doWrite(ChunkedOutputFilter.java:119) 
    at org.apache.coyote.http11.AbstractOutputBuffer.doWrite(AbstractOutputBuffer.java:192) 
    at org.apache.coyote.Response.doWrite(Response.java:504) 
    at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:383) 
    at org.apache.tomcat.util.buf.ByteChunk.append(ByteChunk.java:342) 
    at org.apache.tomcat.util.buf.IntermediateOutputStream.write(C2BConverter.java:278) 
    at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:202) 
    at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:263) 
    at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:106) 
    at java.io.OutputStreamWriter.write(OutputStreamWriter.java:190) 
    at org.apache.tomcat.util.buf.WriteConvertor.write(C2BConverter.java:242) 
    at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:111) 
    at java.io.BufferedWriter.write(BufferedWriter.java:212) 
    at org.apache.tomcat.util.buf.C2BConverter.convert(C2BConverter.java:132) 
    at org.apache.catalina.connector.OutputBuffer.write(OutputBuffer.java:497) 
    at org.apache.catalina.connector.CoyoteWriter.write(CoyoteWriter.java:174) 
    at org.apache.catalina.connector.CoyoteWriter.write(CoyoteWriter.java:184) 
    at org.apache.catalina.connector.CoyoteWriter.print(CoyoteWriter.java:242) 
    at org.apache.catalina.connector.CoyoteWriter.println(CoyoteWriter.java:309) 
    at duplicateserver.request.cotroller.RequestController.sendResponse(RequestController.java:132) 
    at duplicateserver.request.manager.CallLogRestoreManager.processRequest(CallLogRestoreManager.java:35) 
    at duplicateserver.request.handler.DuplicaterRequestHandler.run(DuplicaterRequestHandler.java:46) 
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:439) 
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) 
    at java.util.concurrent.FutureTask.run(FutureTask.java:138) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918) 
    at java.lang.Thread.run(Thread.java:662) 

如何解決? 在此先感謝

+0

請求完成後,您無法依賴寫入者對象的可用性。所以如果這就是你想要做的,你必須以不同的方式做。 – NilsH

+0

同意但如何做到這一點?任何怨言? – Talha

+0

或者,您必須根據內容向您的servlet(輪詢)或websockets發出新請求。 – NilsH

回答

2

拋出一個異常一段時間了,每次都不

這表明一個線程安全問題給我。

你的servlet有一個共享的,可修改的緩存。您從緩存中刪除號碼,但我沒有看到任何同步塊來防止競爭條件。

您可能有一個線程在查找緩存中的數字後輸入該代碼。另一個線程進入並刪除數字,所以儘管第一個線程通過了if測試,但執行該get時,數字已從緩存中消失。

使該操作原子化,看看你是否更好。

@Override 
    public void sendResponse(String number, String data) { 

     System.out.print(number); 
     System.out.println(cache.containsKey(number)); 

     synchronized(this) { 
      if (cache.containsKey(number)) { 
       try { 
        PrintWriter pr = cache.get(number).getWriter(); 
        pr.println(data); 
        pr.close(); 
        cache.remove(number); 
        System.out.println("response sent."); 
        System.out.println("data:" + data); 
       } catch (Exception e) { 
        e.printStackTrace(System.out); 
        System.out.println(e.getMessage()); 
       } 
      } 
     } 
    } 
+0

我正在使用ConcurrentHashMap作爲存儲,這意味着這個問題是與響應拋出異常 – Talha

+0

我不認爲ConcurrentHashMap是足夠的。你必須讓if/get/remove原子。 – duffymo

+0

pr.println(data)寫入數據時發生異常 – Talha