【问题标题】:Making Java Servlet Thread safe使 Java Servlet 线程安全
【发布时间】:2016-10-27 15:20:15
【问题描述】:

我在网页上执行我的 API 时收到了混乱的响应。

回溯了一下,发现 Angular 以正确的方式触发它,但 API 对并发请求的响应不一。

在网上搜索发现Java servlet中的全局变量可能会触发异常行为,因为一个线程可能会访问另一个变量当前正在处理的变量。

说到这里,我意识到PrintWriter 在这里制造了一个问题。但我遇到的困难是如何摆脱问题。

也可能是当前的问题与我的结论完全无关。 请在我错误地导出任何错误的地方纠正我。

@WebServlet(name = "WorkSpaceDetails", urlPatterns = {"/WorkSpaceDetails"})
public class WorkSpaceDetails extends HttpServlet {

    PrintWriter out;
    private static final long serialVersionUID = 1L;


    private void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException, Exception {
        String wid = request.getParameter("id");

        try {

            id = Integer.parseInt(wid);
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            out = response.getWriter();
            Connection conn = null;
            PreparedStatement prx = null;
            PreparedStatement pry = null;
            ResultSet set = null;

            ResultSetMetaData metaData;
            String query;
            JSONObject obj = new JSONObject();
            String WorkSpaceType;
            List<HashMap> completeData = new ArrayList<HashMap>();
            List<String> ColoumnNames = new ArrayList<String>();
            List<String> Data = new ArrayList<String>();
            try {
                query = "-";
                conn = boneCPConnectionPool.getConnection();
                prx = conn.prepareStatement(query);
                prx.setInt(1, id);
                set = prx.executeQuery();
                while (set.next()) {
                    WorkSpaceType = set.getString("WorkSpaceType");
                    System.out.println("WorkSpaceType:" + WorkSpaceType);
                    if (WorkSpaceType.equalsIgnoreCase("1")) {
                        System.out.println("" + 1);
                        query = "-";
                    } else {
                        System.out.println("" + 0);
                        query = "-";
                    }
                    conn = boneCPConnectionPool.getConnection();
                    pry = conn.prepareStatement(query);
                    pry.setInt(1, id);
                    set = pry.executeQuery();
                    metaData = set.getMetaData();
                    int count = metaData.getColumnCount();
                    for (int i = 1; i <= count; i++) {
                        System.out.println("" + metaData.getColumnName(i));
                        ColoumnNames.add(metaData.getColumnName(i));
                    }
                    while (set.next()) {
                        HashMap tmp = new HashMap();
                        for (int i = 0; i < ColoumnNames.size(); i++) {

                            String cname = ColoumnNames.get(i);

                            tmp.put(cname, set.getString(cname));
                            tmp.put("WorkSpaceType", WorkSpaceType);
                        }
                        System.out.println("" + tmp);
                        completeData.add(tmp);
                        generateJson(completeData);
                    }


                }

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

                if (conn != null) {
                    try {
                        conn.close();
                    } catch (Exception e) {
                    }
                }
                if (set != null) {
                    try {
                        set.close();
                    } catch (SQLException ignore) {
                    }
                }
                if (prx != null) {
                    try {
                        prx.close();
                    } catch (SQLException ignore) {
                    }
                }
                if (pry != null) {
                    try {
                        pry.close();
                    } catch (SQLException ignore) {
                    }
                }

            }
        } catch (Exception e) {

            JSONObject obj = new JSONObject();
            obj.put("Error", "BLANK ID");
            System.out.println(obj.toString());
            e.printStackTrace();
        }
    }

    private void generateJson(List<HashMap> data) {
        JSONObject obj = new JSONObject();
        try {
            for (HashMap map : data) {

                Iterator it = map.entrySet().iterator();

                while (it.hasNext()) {

                    Map.Entry pair = (Map.Entry) it.next();
                    String key = (String) pair.getKey();

                    String value = (String) pair.getValue();
                    if (value == null) {
                        value = "blank";
                    }
                    obj.put(key, value);
                }
            }

            out.println(obj.toString());

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        out = response.getWriter();
        JSONObject obj = new JSONObject();
        try {
            obj.put("Error", "API Protected Get Request");
        } catch (JSONException ex) {
            Logger.getLogger(WorkSpaceDetails.class.getName()).log(Level.SEVERE, null, ex);
        }
        out.println(obj.toString());
        out.close();
        System.out.println("API Protected:Get Request");
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        out = response.getWriter();
        JSONObject obj = new JSONObject();
        try {
            processRequest(request, response);
        } catch (NumberFormatException ex) {
            try {
                obj.put("Error", "ID NULL");
            } catch (JSONException ex1) {
                Logger.getLogger(WorkSpaceDetails.class.getName()).log(Level.SEVERE, null, ex1);
            }
            out.println(obj.toString());
        } catch (Exception ex) {

            try {
                obj.put("Error", "TOKEN NULL");
            } catch (JSONException ex1) {
                Logger.getLogger(WorkSpaceDetails.class.getName()).log(Level.SEVERE, null, ex1);
            }
            out.println(obj.toString());
            out.close();

        }
    }

    @Override
    public String getServletInfo() {
        return "Servlet to get info of a Workspace";
    }

}

【问题讨论】:

    标签: java multithreading servlets


    【解决方案1】:

    不要将PrintWriter out; 声明为类成员,而是将其作为processRequest() 中的局部变量,就像您已经在doGet()doPost() 中所做的那样。这样,可能同时访问 servlet 的多个线程不会相互干扰。

    更新

    看来processRequest()是从doPost()调用的,所以建议你:

    • 摆脱PrintWriter out类成员
    • doGet() 中声明一个本地PrintWriter out
    • doPost() 中声明一个本地PrintWriter out
    • out作为参数传递给processRequest(),其签名可能是:
    private void processRequest(
        HttpServletRequest request, HttpServletResponse response, PrintWriter out);
    

    更新

    • out 作为参数传递给generateJson()
    • out 作为参数传递给processRequest() 处的“generateJson”方法调用

    private void generateJson(List&lt;HashMap&gt; data, PrintWriter out);

    generateJson(completeData, out);

    【讨论】:

    • 如果我这样做,逻辑会中断数据流,因为范围仅限于定义它们的方法。servlet 不提供任何响应。
    • @AkshayR。那很奇怪。从你贴的代码sn-p来看,PrintStream out只用在processRequest()方法中,所以按照我的建议做是没有问题的
    • 已将代码更新为功能性代码。请查看 doget() 和 dopost() 方法
    • @AkshayR。更新了我的答案。顺便说一句,那个类还没有编译
    • 太棒了。我的工作和这个解决方案在我的情况下不起作用的问题是,一个额外的方法 generateJson 需要 out 作为参数,然后需要在 processRequest() 方法对 generateJson 的调用中传递该参数。会将其添加到您的最终答案中。
    【解决方案2】:

    您必须解决此问题的两个选项如下:

    1. PrintWriter 移动到需要它的方法中的局部变量。

    2. 如果您绝对必须将其作为实例/类变量,请使用ThreadLocal 变量。使用ThreadLocal 将允许访问您的servlet 的每个线程拥有自己的PrintWriter 实例。

    ThreadLocal

    希望这会有所帮助!

    【讨论】:

    • 这也符合我的想法。但在我的情况下没有。不知道为什么。这就是我一直在寻找的,这样我就可以毫不费力地解决我的问题。还是谢谢。
    猜你喜欢
    • 2010-11-14
    • 1970-01-01
    • 2016-08-24
    • 2012-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多