关于threadLocal的使用中出现NullPointException的解决方案

在项目日志拦截器中使用了threadlocal,在记录日志时,

private static final ThreadLocal<Long> startTimeThreadLocal =
			new NamedThreadLocal<Long>("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 nullThreadLocal 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<Long> startTimeThreadLocal =
    			new NamedThreadLocal<Long>("ThreadLocal StartTime"){
    		protected Long initialValue() {
    			Logger logger = LoggerFactory.getLogger(getClass());
    			logger.info("ThreadLocal StartTime initialValue");
    			long beginTime = System.currentTimeMillis();
    			return beginTime;
    			
    		};
    	};




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值