简体   繁体   English

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

[英]Why should I avoid using InheritableThreadLocal in servlets?

I am using InheritableThreadLocal in my Servlet Class. 我在Servlet类中使用了InheritableThreadLocal So that It will available from it's child threads. 因此它可以从它的子线程中获得。 Is that evil using InheritableThreadLocal in thread pool executors? 在线程池执行程序中使用InheritableThreadLocal是邪恶的吗? . Such as servlet thread pool. 比如servlet线程池。

My Questions. 我的问题。

1) Why should we avoid using InheritableThreadLocals in servlets? 1)为什么我们要避免在servlets中使用InheritableThreadLocals

2) Is this memory leak possible in InheritableThreadLocal ? 2)在InheritableThreadLocal是否可以进行内存泄漏?

3) Is there any alternative for InheritableThreadLocal ?. 3) InheritableThreadLocal还有其他选择吗?

4) What happens if the thread will be reused , the value stored in threadlocal will not be cleared? 4)如果线程将被重用会发生什么, threadlocal存储的值将不会被清除?

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) . 过滤器 - > Servlet A - >子线程--->邮件线程(这里我得到过滤器中设置的值)。

Why should we avoid using InheritableThreadLocals in servlets? 为什么我们要避免在servlet中使用InheritableThreadLocals?

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? 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? 是否有任何替代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. 如果线程将被重用会发生什么,threadlocal中存储的值将不会被清除。

It won't be cleared. 它不会被清除。 THAT is the problem! 那就是问题所在!

Your example works, the MailThread inherits the value of currentRequestURI when it is created. 您的示例有效, MailThread在创建时继承 currentRequestURI的值。

But the UserAccessFilter and the java.lang.InheritableThreadLocal just serve to confuse what the code is trying to do, which is the evil part. UserAccessFilterjava.lang.InheritableThreadLocal只是混淆了代码试图做的事情,这是邪恶的部分。

What's wrong changing the constructor of MailThread so that you can pass the request URI from the MailServlet like this: 更改MailThread的构造函数有什么问题,以便您可以从MailServlet传递请求URI,如下所示:

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. 那么你不需要本地的线程,你不需要过滤器,代码更清晰。

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

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