简体   繁体   English

使Java Servlet线程安全

[英]Making Java Servlet Thread safe

I've been getting mixed up responses on the execution of my API from webpage. 我对网页执行API的反应一直很混乱。

Backtracked a little and found out, Angular was firing it the right way, but the API responded with mixed responses for concurrent requests. 回溯了一点,发现了,Angular正确地触发了它,但是API响应了并发请求的混合响应。

Searched the internet found out Global variables in Java servlet may trigger the abnormal behavior as one thread might access the variable currently being processed by another variable. 在互联网上搜索发现Java servlet中的全局变量可能会触发异常行为,因为一个线程可能会访问另一变量当前正在处理的变量。

So coming to the point I realized PrintWriter is creating a problem here. 因此,我意识到PrintWriter在这里造成了问题。 But what I'm experiencing a difficulty with is how to get out of the problem. 但是我遇到的困难是如何解决这个问题。

And also may be the current problem is not at all related to my conclusions. 也可能是当前的问题与我的结论根本无关。 Please correct me wherever I've wrongly derived anything wrong. 如果我错误地得出任何错误,请纠正我。

@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";
    }

}

Instead of declaring PrintWriter out; 而不是声明PrintWriter out; as a class member, do it as a local variable inside processRequest() , like you're already doing in doGet() and doPost() . 作为类成员,请将其作为processRequest()的局部变量进行,就像您已经在doGet()doPost()所做的那样。 This way, the multiple threads that may access the servlet concurrently won't interfere with each other. 这样,可以同时访问servlet的多个线程不会互相干扰。

UPDATE UPDATE

It seems that processRequest() is only called from doPost() , so I suggest you to: 看来processRequest()仅从doPost()调用,所以我建议您:

  • Get rid of PrintWriter out class member 摆脱PrintWriter out类成员
  • Declare a local PrintWriter out in doGet() doGet()声明本地PrintWriter out
  • Declare a local PrintWriter out in doPost() doPost()声明一个本地PrintWriter out
  • Pass out as a parameter to processRequest() , whose signature may be: 传递out作为参数processRequest()其签名可能是:
private void processRequest(
    HttpServletRequest request, HttpServletResponse response, PrintWriter out);

UPDATE UPDATE

  • Pass out as a parameter to generateJson() 传递out作为参数传递给generateJson()
  • Pass out as a parameter to call made to 'generateJson' method at processRequest() 作为参数传递out ,以在processRequest()对“ generateJson”方法进行调用

private void generateJson(List<HashMap> data, PrintWriter out);

generateJson(completeData, out);

Two of the options you have to fix this issue are as follows: 您必须解决此问题的两个选项如下:

  1. Move PrintWriter to local variables inside methods that need it. PrintWriter移到需要它的方法内的局部变量。

  2. If you absolutely have to have it as an instance/class variable then use a ThreadLocal variable. 如果您绝对必须将其作为实例/类变量,请使用ThreadLocal变量。 Using ThreadLocal would allow each thread accessing your servlet to have its own PrintWriter instance. 使用ThreadLocal将允许每个访问您的servlet线程拥有自己的PrintWriter实例。

ThreadLocal ThreadLocal的

Hope this helps! 希望这可以帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM