有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java通过静态或非静态方法使用ThreadLocal的最佳方式是什么?

对于我的应用程序,我必须将某些信息带到应用程序的每一层(一个示例可能是为传入请求生成的唯一事务id)

因此,我计划创建一个引用ThreadLocal<ConcurrentMap<String, Object>>的类

感激有人能帮助;我有一个困惑,出于以下方法,哪一个更好:

1。AppContext。具有静态方法的java

public final class AppContext {
  private static final ThreadLocal&lt;ConcurrentMap&lt;String, Object&gt;&gt; context = new ThreadLocal<>();

  public static void set(final String key, final Object value) {
    // set key value in thread local
  }

  public static Object get(final String key) {
    // get value from thread local
  }
}

2。AppContext。具有非静态方法的java

public final class AppContext {
  private static final ThreadLocal&lt;ConcurrentMap&lt;String, Object&gt;&gt; context = new ThreadLocal<>();

  public void set(final String key, final Object value) {
    // set key value in thread local
  }

  public Object get(final String key) {
    // get value from thread local
  }
}

共 (3) 个答案

  1. # 1 楼答案

    没有使用ThreadLocal的最佳方法。将其视为“全球变量”,以及由此产生的一切负面影响。这是地球上的一个水痘。你的应用程序中的一种癌症,总有一天会吞噬你。不惜一切代价避免它。学习如何通过适当的不可变状态,让你的线程烦恼消失

  2. # 2 楼答案

    尽管其他人可能会说,ThreadLocal变量并不是天生邪恶的,它们只是在使用时需要一些额外的注意和理解。线程安全并不是真正相关的,因为它们本质上与一个线程相关。当这些线程可能被应用程序的其他不同用户重用时,就会出现问题。在基于Java的web应用程序中,情况就是这样;但是,一次只能有一个用户/请求在该线程上运行。非常重要的一步是确保在每个请求结束时清理ThreadLocal对象

    因此,为了避免不必要地为每个请求实例化一个新的上下文,我建议创建多个静态类型安全的ThreadLocal对象,所有这些对象都生活在一个“上下文”类中,这些对象以某种方式相互关联。可以使用多个上下文类来组织这些上下文项的不同组

    然而,本着ThreadLocal批评者的精神,我同意ThreadLocals应该少用一些,过度使用可能是一种代码气味

    以下是上述方法的一个例子

    上下文类

    public class LogContext {
    
        private static ThreadLocal<String> localCorrelationId = new ThreadLocal<String>();
        private static ThreadLocal<String> localUserId = new ThreadLocal<String>();
    
        public static String getCorrelationId() {
            return localCorrelationId.get();
        }
    
        public static void setCorrelationId(String correlationId) {
            localCorrelationId.set(correlationId);
        }
    
        public static String getUserId() {
            return localUserId.get();
        }
    
        public static void setUserId(String userId) {
            localUserId.set(userId);
        }
    
        public static void cleanup() {
            localCorrelationId.remove();
            localUserId.remove();
        }
    }
    

    通过Servlet过滤器管理上下文

    @WebFilter(filterName = "LogContextFilter", urlPatterns = {"/*"})
    public class LogContextFilter implements Filter {
    
        public void init(FilterConfig filterConfig) {
    
        }
    
        public void doFilter(ServletRequest request, ServletResponse response,
                FilterChain chain)
                throws IOException, ServletException {
    
            try {
                LogContext.setCorrelationId(UUID.randomUUID().toString());
                chain.doFilter(request, response);
            } catch (Throwable t) {
                t.printStackTrace();
            } finally {
                //This is critical!
                LogContext.cleanup();
            }
    
        }
    
        public void destroy() {
    
        }
    
    }
    

    访问上下文(例如从Servlet)

    @WebServlet(name = "SimpleServlet", urlPatterns = {"/SimpleServlet"})
    public class SimpleServlet extends HttpServlet {
    
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
    
            String correlationId = LogContext.getCorrelationId();
        }
    
    }
    
  3. # 3 楼答案

    如果AppContext是单例,那么静态方法是最好的方法。如果有多个AppContext,那么应该让这些方法是非静态的