A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

  在项目日志拦截器中使用了threadlocal,在记录日志时,
  private static final ThreadLocal startTimeThreadLocal =
  new NamedThreadLocal("ThreadLocal StartTime");
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
  Object handler) throws Exception {
  if (logger.isDebugEnabled()){
  long beginTime = System.currentTimeMillis();//1、开始时间
  startTimeThreadLocal.set(beginTime); //线程绑定变量(该数据只有当前请求的线程可见)
  logger.debug("开始计时: {} URI: {}", new SimpleDateFormat("hh:mm:ss.SSS")
  .format(beginTime), request.getRequestURI());
  }
  return true;
  }
  @Override
  public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
  Object handler, Exception ex) throws Exception {
  // 打印JVM信息。
  if (logger.isDebugEnabled()){
  long beginTime = startTimeThreadLocal.get();//得到线程绑定的局部变量(开始时间)
  long endTime = System.currentTimeMillis(); //2、结束时间
  logger.debug("计时结束:{} 耗时:{} URI: {} 最大内存: {}m 已分配内存: {}m 已分配内存中的剩余空间: {}m 最大可用内存: {}m",
  new SimpleDateFormat("hh:mm:ss.SSS").format(endTime), DateUtil.formatDateTime(endTime - beginTime),
  request.getRequestURI(), Runtime.getRuntime().maxMemory()/1024/1024, Runtime.getRuntime().totalMemory()/1024/1024, Runtime.getRuntime().freeMemory()/1024/1024,
  (Runtime.getRuntime().maxMemory()-Runtime.getRuntime().totalMemory()+Runtime.getRuntime().freeMemory())/1024/1024);
  //删除线程变量中的数据,防止内存泄漏
  startTimeThreadLocal.remove();
  }
  由于过滤器filter的拦截是的没有直接访问preHandle方法,所以ThreadLocal没有set值,就直接访问afterCompletion从ThreadLocal中get值,导致ThreadLocal底层使用的map为空,执行initialValue方法并抛出NullPointException,根据jdk文档推荐做法
  ---------------------

  Method Detail
  initialValue
  protected T initialValue()
  Returns the current thread's "initial value" for this thread-local variable. This method will be invoked the first time a thread accesses the variable with the get() method, unless the thread previously invoked the set(T) method, in which case the initialValue method will not be invoked for the thread. Normally, this method is invoked at most once per thread, but it may be invoked again in case of subsequent invocations of remove() followed by get().
  This implementation simply returns null; if the programmer desires thread-local variables to have an initial value other than null, ThreadLocal must be subclassed, and this method overridden. Typically, an anonymous inner class will be used.
  Returns:
  the initial
  value for this thread-local
  采取如下解决方案,事实证明,该initialValue确实执行,并不在抛出NullPointException,但另外在项目中就存在为什么被过滤器拦截后执行发生变化,不是先执行prehandle再执行aftercompletion,而是出现反复执行aftercompletion的问题待解决
  private static final ThreadLocal startTimeThreadLocal =
  new NamedThreadLocal("ThreadLocal StartTime"){
  protected Long initialValue() {
  Logger logger = LoggerFactory.getLogger(getClass());
  logger.info("ThreadLocal StartTime initialValue");
  long beginTime = System.currentTimeMillis();
  return beginTime;
  };
  };
  ---------------------


0 个回复

您需要登录后才可以回帖 登录 | 加入黑马