如何使用Listener发送Servlet响应

时间:2013-05-22 09:31:23

标签: java servlets

我正在开发具有以下场景的多线程java sevlet 数据来自不同的块,为此我只需要在最后一个请求中发送响应。 数据块转发到其他类以保存数据。

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代码。 cache是​​一个静态存储器,我用它来收到所有请求后发送响应

我还有一个列表器,告诉sevlet请求已完成

public interface ResponseHandler {

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

及其在RequestController中的实现是

 @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)

如何解决? 提前致谢

1 个答案:

答案 0 :(得分: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());
                }
            }
        }
    }