java中ThreadLocal的应用场景实例分析
说到线程的安全,我们可以通过ThreadLocal来解决。但作为一种强大的变量,它的应用场景远不止如此。在各类的框架中,我们依然可以使用来对它们进行管理。同时在使用ThreadLocal时需要注意内存泄漏的问题。下面我们就这两点进行分析,并带来对应代码的展示。
1、各种框架中的应用
Spring框架的事务管理中使用ThreadLocal来管理连接,每个线程是单独的连接,当事务失败时不能影响到其他线程的事务过程或结果,还有大家耳闻目睹的ORM框架、Mybatis也是用ThreadLocal管理,SqlSession也是如此。
//SpringTransactionSynchronizationManager类 @Override protectedvoiddoBegin(Objecttransaction,TransactionDefinitiondefinition){ DataSourceTransactionObjecttxObject=(DataSourceTransactionObject)transaction; Connectioncon=null; try{ //此处省略N行代码 if(txObject.isNewConnectionHolder()){ //绑定数据库连接到线程中 TransactionSynchronizationManager.bindResource(obtainDataSource(),txObject.getConnectionHolder()); } } catch(Throwableex){ if(txObject.isNewConnectionHolder()){ //当发生异常时,移除线程中的连接 DataSourceUtils.releaseConnection(con,obtainDataSource()); txObject.setConnectionHolder(null,false); } thrownewCannotCreateTransactionException("CouldnotopenJDBCConnectionfortransaction",ex); } }
2、防止内存泄漏
通常我们是使用如下的方式操作ThreadLocal,在使用完threadlocal后一定要remove掉,防止内存泄露。
privatestaticfinalThreadLocalloginUserLocal=newThreadLocal (); publicstaticLoginUsergetLoginUser(){ returnloginUserLocal.get(); } publicstaticvoidsetLoginUser(LoginUserloginUser){ loginUserLocal.set(loginUser); } publicstaticvoidclear(){ loginUserLocal.remove(); } //在使用完后一定要清理防止内存泄露 try{ loginUserLocal.set(loginUser); //执行其他业务逻辑 }finally{ loginUserLocal.remove(); }
java中ThreadLocal实例扩展:
/** *日期工具类(使用了ThreadLocal获取SimpleDateFormat,其他方法可以直接拷贝common-lang) *@authorNiuLi *@date2016/11/19 */ publicclassDateUtil{ privatestaticMap>sdfMap=newHashMap >(); privatestaticLoggerlogger=LoggerFactory.getLogger(DateUtil.class); publicfinalstaticStringMDHMSS="MMddHHmmssSSS"; publicfinalstaticStringYMDHMS="yyyyMMddHHmmss"; publicfinalstaticStringYMDHMS_="yyyy-MM-ddHH:mm:ss"; publicfinalstaticStringYMD="yyyyMMdd"; publicfinalstaticStringYMD_="yyyy-MM-dd"; publicfinalstaticStringHMS="HHmmss"; /** *根据map中的key得到对应线程的sdf实例 *@parampatternmap中的key *@return该实例 */ privatestaticSimpleDateFormatgetSdf(finalStringpattern){ ThreadLocal sdfThread=sdfMap.get(pattern); if(sdfThread==null){ //双重检验,防止sdfMap被多次put进去值,和双重锁单例原因是一样的 synchronized(DateUtil.class){ sdfThread=sdfMap.get(pattern); if(sdfThread==null){ logger.debug("putnewsdfofpattern"+pattern+"tomap"); sdfThread=newThreadLocal (){ @Override protectedSimpleDateFormatinitialValue(){ logger.debug("thread:"+Thread.currentThread()+"initpattern:"+pattern); returnnewSimpleDateFormat(pattern); } }; sdfMap.put(pattern,sdfThread); } } } returnsdfThread.get(); } /** *按照指定pattern解析日期 *@paramdate要解析的date *@parampattern指定格式 *@return解析后date实例 */ publicstaticDateparseDate(Stringdate,Stringpattern){ if(date==null){ thrownewIllegalArgumentException("Thedatemustnotbenull"); } try{ returngetSdf(pattern).parse(date); }catch(ParseExceptione){ e.printStackTrace(); logger.error("解析的格式不支持:"+pattern); } returnnull; } /** *按照指定pattern格式化日期 *@paramdate要格式化的date *@parampattern指定格式 *@return解析后格式 */ publicstaticStringformatDate(Datedate,Stringpattern){ if(date==null){ thrownewIllegalArgumentException("Thedatemustnotbenull"); }else{ returngetSdf(pattern).format(date); } } }
到此这篇关于java中ThreadLocal的应用场景实例分析的文章就介绍到这了,更多相关java中ThreadLocal的应用场景浅析内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!