为什么我要避免在servlet中使用InheritableThreadLocal?

时间:2013-01-24 10:01:26

标签: java tomcat servlets thread-safety

我在InheritableThreadLocal班级中使用Servlet。因此它可以从它的子线程中获得。在线程池执行器中使用InheritableThreadLocal是邪恶的吗? 。比如servlet线程池。

我的问题。

1)为什么我们要避免在servlet中使用InheritableThreadLocals

2)InheritableThreadLocal

中是否存在内存泄漏问题

3)InheritableThreadLocal还有其他选择吗?

4)如果线程被重用会发生什么,threadlocal中存储的值将不会被清除?

我的实时情景

public class UserAccessFilter implements javax.servlet.Filter {

      static final InheritableThreadLocal<String> currentRequestURI = new InheritableThreadLocal<String>();

      public void  doFilter(ServletRequest req, ServletResponse resp , FilterChain fc) throws IOException, ServletException{
              String uri = request.getRequestURI();
              fc.doFilter(request, response);         
      }
}


public class MailServlet extends HttpServlet{

      @Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String mailCount = req.getParameter("mailCount");

    if(mailCount != null && !"".equals(mailCount) && mailCount.matches("[0-9]+")){
        MailThread mailThread = new MailThread("xxx@gmail.com", generateToAddress(Integer.parseInt(mailCount))); //NO I18N
        Thread t = new Thread(mailThread);
        t.start();
    }

    resp.getWriter().println("Mail Servlet.............."); //NO I18N

}              

}

class MailThread implements Runnable{

private String from;
private String to;

public MailThread(String from , String to){
    this.from = from;
    this.to = to;
}


@Override
public void run() {
    sendMail();
}

    public void sendMail(){
        //I want this uri from child threads. I can't pass this value to this constructor.
        String uri = currentRequestURI.get();
        //Do Mail Operations
    }


}

过滤器 - &gt; Servlet A - &gt;儿童线程---&gt;邮件线程(这里我得到过滤器中设置的值)。

2 个答案:

答案 0 :(得分:10)

  

为什么我们要避免在servlet中使用InheritableThreadLocals?

它们代表了将信息从一个请求泄露到另一个请求的潜在途径。 “问题”是请求由线程池处理。当请求完成时,线程处理的下一个请求可能是针对不同的用户。但是如果你在完成第一个请求时忘记清除线程本地状态,那么第二个请求可能会使用它。

  

InheritableThreadLocal是否可能发生内存泄漏?

是的......有点儿。如果我们假设工作池是有界的,则任何线程的线程本地状态都可能被覆盖,从而清除内存泄漏。在最坏的情况下,问题是有限的内存泄漏......受池中线程数量的限制。

信息泄漏问题更令人担忧。

  

InheritableThreadLocal还有其他选择吗?

在请求或响应对象中设置属性更好。

  

如果线程将被重用会发生什么,threadlocal中存储的值将不会被清除。

不会被清除。这就是问题!

答案 1 :(得分:0)

您的示例有效,MailThread 在创建时currentRequestURI继承

但是UserAccessFilterjava.lang.InheritableThreadLocal只会混淆代码尝试做的事情,这是邪恶的部分。

更改MailThread的构造函数有什么问题,以便您可以像MailServlet那样传递请求URI:

MailThread mailThread = new MailThread("xxx@gmail.com", generateToAddress(Integer.parseInt(mailCount)), req.getRequestURI());

然后你不需要本地的线程,你不需要过滤器,代码更清晰。