java中ThreadLocal的应用场景实例分析

网友投稿 232 2023-02-01

java中ThreadLocal的应用场景实例分析

说到线程的安全,我们可以通过ThreadLocal来解决。但作为一种强大的变量,它的应用场景远不止如此。在各类的框架中,我们依然可以使用来对它们进行管理。同时在使用ThreadLocal时需要注意内存泄漏的问题。下面我们就这两点进行分析,并带来对应代码的展示。

1、各种框架中的应用

Spring框架的事务管理中使用ThreadLocal来管理连接,每个线程是单独的连接,当事务失败时不能影响到其他线程的事务过程或结果,还有大家耳闻目睹的ORM框架、Mybatis也是用ThreadLocal管理,SqlSession也是如此。

//Spring TransactionSynchronizationManager类

@Override

protected void doBegin(Object transaction, TransactionDefinition definition) {

DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;

Connection con = null;

try {

//此处省略N行代码

if (txObject.isNewConnectionHolder()) {

//绑定数据库连接到线程中

TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());

}

}

catch (Throwable ex) {

if (txObject.isNewConnectionHolder()) {

//当发生异常时,移除线程中的连接

DataSourceUtils.releaseConnection(con, obtainDataSource());

txObject.setConnectionHolder(null, false);

}

throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);

}

}

2、防止内存泄漏

通常我们是使用如下的方式操作ThreadLocal,在使用完threadlocal后一定要remove掉,防止内存泄露。

private static final ThreadLocal loginUserLocal = new ThreadLocal();

public static LoginUser getLoginUser() {

return loginUserLocal.get();

}

public static void setLoginUser(LoginUser loginUser) {

loginUserLocal.set(loginUser);

}

public static void clear() {

loginUserLocal.remove();

}

//在使用完后一定要清理防止内存泄露

try{

loginUserLocal.set(loginUser);

//执行其他业务逻辑

}finally{

loginUserLocal.remove();

}

java中ThreadLocal实例扩展:

/**

* 日期工具类(使用了ThreadLocal获取SimpleDateFormat,其他方法可以直接拷贝common-lang)

* @author Niu Li

* @date 2016/11/19

*/

public class DateUtil {

private static Map> sdfMap = new HashMap>();

private static Logger logger = LoggerFactory.getLogger(DateUtil.class);

public final static String MDHMSS = "MMddHHmmssSSS";

public final static String YMDHMS = "yyyyMMddHHmmss";

public final static String YMDHMS_ = "yyyy-MM-dd HH:mm:ss";

public final static String YMD = "yyyyMMdd";

public final static String YMD_ = "yyyy-MM-dd";

public final static String HMS = "HHmmss";

/**

* 根据map中的key得到对应线程的sdf实例

* @param pattern map中的key

* @return 该实例

*/

private static SimpleDateFormat getSdf(final String pattern){

ThreadLocal sdfThread = sdfMap.get(pattern);

if (sdfThread == null){

//双重检验,防止sdfMap被多次put进去值,和双重锁单例原因是一样的

synchronized (DateUtil.class){

sdfThread = sdfMap.get(pattern);

if (sdfThread == null){

logger.debug("put new sdf of pattern " + pattern + " to map");

sdfThread = new ThreadLocal(){

@Override

protected SimpleDateFormat initialValue() {

logger.debug("thread: " + Thread.currentThread() + " init pattern: " + pattern);

return new SimpleDateFormat(pattern);

}

};

sdfMap.put(pattern,sdfThread);

}

}

}

return sdfThread.get();

}

/**

* 按照指定pattern解析日期

* @param date 要解析的date

* @param pattern 指定格式

* @return 解析后date实例

*/

public static Date parseDate(String date,String pattern){

if(date == null) {

throw new IllegalArgumentException("The date must not be null");

}

try {

return getSdf(pattern).parse(date);

} catch (ParseException e) {

e.printStackTrace();

logger.error("解析的格式不支持:"+pattern);

}

return null;

}

/**

* 按照指定pattern格式化日期

* @param date 要格式化的date

* @param pattern 指定格式

* @return 解析后格式

*/

public static String formatDate(Date date,String pattern){

if (date == null){

throw new IllegalArgumentException("The date must not be null");

}else {

return getSdf(pattern).format(date);

}

}

}

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:京东联盟开放api接口(京东联盟开放api接口有哪些)
下一篇:手把手教你从零设计一个java日志框架
相关文章

 发表评论

暂时没有评论,来抢沙发吧~