2013-05-22 45 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