简体   繁体   中英

Why should I avoid using InheritableThreadLocal in servlets?

I am using InheritableThreadLocal in my Servlet Class. So that It will available from it's child threads. Is that evil using InheritableThreadLocal in thread pool executors? . Such as servlet thread pool.

My Questions.

1) Why should we avoid using InheritableThreadLocals in servlets?

2) Is this memory leak possible in InheritableThreadLocal ?

3) Is there any alternative for InheritableThreadLocal ?.

4) What happens if the thread will be reused , the value stored in threadlocal will not be cleared?

My Real Time Scenario

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
    }


}

Filter --> Servlet A --> Child Thread ---> Mail Thread (Here I am getting the value setted in filter) .

Why should we avoid using InheritableThreadLocals in servlets?

They represent a potential path for leaking information from one request to another. The "problem" is that requests are handled by a pool of threads. When on request is completed, the next request that a thread handles is likely to be for a different user. But if you forget to clear the thread local state on finishing the first request, there is a potential that it might be used by the second one.

Is a memory leak possible in InheritableThreadLocal?

Yes ... sort of. If we assume that the worker pool is bounded, the thread local state of any thread is likely to be overwritten, clearing the memory leak. At worst the problem is a bounded memory leak ... bounded by the number of threads in the pool.

The information leakage problem is more concerning.

Is there any alternative for InheritableThreadLocal?

Setting attributes in the request or response object is better.

What happens if the thread will be reused, the value stored in threadlocal will not be cleared.

It won't be cleared. THAT is the problem!

Your example works, the MailThread inherits the value of currentRequestURI when it is created.

But the UserAccessFilter and the java.lang.InheritableThreadLocal just serve to confuse what the code is trying to do, which is the evil part.

What's wrong changing the constructor of MailThread so that you can pass the request URI from the MailServlet like this:

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

Then you have no need for a thread local, you don't need the filter and the code is clearer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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