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<LoginUser> loginUserLocal = new ThreadLocal<LoginUser>();
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<String,ThreadLocal<SimpleDateFormat>> sdfMap = new HashMap<String, ThreadLocal<SimpleDateFormat>>();

 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<SimpleDateFormat> 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<SimpleDateFormat>(){
      @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);
  }
 }
}

到此这篇关于java中ThreadLocal的应用场景实例分析的文章就介绍到这了,更多相关java中ThreadLocal的应用场景浅析内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java单线程ThreadLocal串值问题解决方案

    ThreadLocal ThreadLocal 适用于变量在线程间隔离,而在方法或类间共享的场景. 代码 @RestController public class ThreadLocalController { private static final ThreadLocal<String> currentUid = ThreadLocal.withInitial(() -> null); @GetMapping("bad") public Map doBad(@Re

  • Java中的ThreadLocal功能演示示例

    除了使用synchronized同步符号外,Java中的ThreadLocal是另一种实现线程安全的方法.在进行性能测试用例的编写过程中,比较简单的办法就是直接使用synchronized关键字,修饰对象.方法以及类.但是使用synchronized同步,这可能会影响应用程序的可伸缩性以及运行效率.但是如果要在多个线程之间共享对象又要保障线程安全,则除了synchronized之外没有特别适合测试的方法. Java中的ThreadLocal是实现线程安全的另一种方法,它不满足同步要求,而是通过为

  • java中ThreadLocalRandom的使用详解

    在java中我们通常会需要使用到java.util.Random来便利的生产随机数.但是Random是线程安全的,如果要在线程环境中的话就有可能产生性能瓶颈. 我们以Random中常用的nextInt方法为例来具体看一下: public int nextInt() { return next(32); } nextInt方法实际上调用了下面的方法: protected int next(int bits) { long oldseed, nextseed; AtomicLong seed = t

  • java中ThreadLocal取不到值的两种原因

    1.两种原因 第一种,也是最常见的一种,就是多个线程使用ThreadLocal 第二种,类加载器不同造成取不到值,本质原因就是不同类加载器造成多个ThreadLocal对象 public class StaticClassLoaderTest { protected static final ThreadLocal<Object> local = new ThreadLocal<Object>(); //cusLoader加载器加载的对象 private Test3 test3;

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

    说到线程的安全,我们可以通过ThreadLocal来解决.但作为一种强大的变量,它的应用场景远不止如此.在各类的框架中,我们依然可以使用来对它们进行管理.同时在使用ThreadLocal时需要注意内存泄漏的问题.下面我们就这两点进行分析,并带来对应代码的展示. 1.各种框架中的应用 Spring框架的事务管理中使用ThreadLocal来管理连接,每个线程是单独的连接,当事务失败时不能影响到其他线程的事务过程或结果,还有大家耳闻目睹的ORM框架.Mybatis也是用ThreadLocal管理,S

  • Java中List与数组相互转换实例分析

    本文实例分析了Java中List与数组相互转换的方法.分享给大家供大家参考.具体如下: 今天写代码遇到一个奇怪的问题,具体代码不贴出了,写一个简化的版本.如下: ArrayList<String> list=new ArrayList<String>(); String strings[]=(String [])list.toArray(); 这样写代码个人觉得应该没什么问题,编译也没有问题.可是具体运行的时候报异常,如下:Exception in thread "mai

  • Java中对象的比较操作实例分析

    本文实例讲述了Java中对象的比较操作.分享给大家供大家参考,具体如下: 一 点睛 在Java中,有两种方式可用于对象间的比较: 利用"=="运算符:用于比较两个对象的内存地址值(引用值)是否相等. 利用equals()方法:用于比较两个对象的内容是否一致. 二 "=="运算符的比较 1 代码 public class CompareObject1 { public static void main( String[] args ) { String str1 =

  • Java中final与继承操作实例分析

    本文实例讲述了Java中final与继承操作.分享给大家供大家参考,具体如下: 一 点睛 final在Java中被称为终结器. 1 在基类的某个方法加了final,那么在子类中该方法被禁止二次"改造". 2 通过在类的前面添加final关键字,便可以阻止基类被继承. 二 实战1--final标记的方法不能被子类覆写实例 1 代码 class Person { // 此方法声明为final不能被子类覆写 final public String talk() { return "

  • java 中ThreadLocal实例分析

    java  中ThreadLocal实例分析 从概念上理解,threadlocal使变量在多个线程中相互隔离实现线程安全,threadlocal包装的变量最终都专属于对应的每个线程,线程之间相互独立,用一个具体实现来说明: public interface Consumer { int consume(); } public class ComsumeThread implements Runnable { private Consumer consumer; public ComsumeThr

  • java  中ThreadLocal实例分析

    java  中ThreadLocal实例分析 从概念上理解,threadlocal使变量在多个线程中相互隔离实现线程安全,threadlocal包装的变量最终都专属于对应的每个线程,线程之间相互独立,用一个具体实现来说明: public interface Consumer { int consume(); } public class ComsumeThread implements Runnable { private Consumer consumer; public ComsumeThr

  • Java中ThreadLocal 导致内存 OOM 的原因分析

    目录 原因分析 正确的使用方式 原因分析 ThreadLocal 导致内存 OOM 的原因是什么? ThreadLocal 底层通过 ThreadLocalMap 存储数据 源码如下:  当我们使用ThreadLocal.set()时,set的value与key(即业务自己定义的ThreadLocal类)会存储在ThreadLocalMap的Entry[]数组里 源码如下: 其中Entry是实现了一个弱引用WeakReference,Entry的key(即业务方定义的 ThreadLocal类)

  • 快速了解Java中ThreadLocal类

    最近看Android FrameWork层代码,看到了ThreadLocal这个类,有点儿陌生,就翻了各种相关博客一一拜读:自己随后又研究了一遍源码,发现自己的理解较之前阅读的博文有不同之处,所以决定自己写篇文章说说自己的理解,希望可以起到以下作用: - 可以疏通研究结果,加深自己的理解: - 可以起到抛砖引玉的作用,帮助感兴趣的同学疏通思路: - 分享学习经历,同大家一起交流和学习. 一. ThreadLocal 是什么 ThreadLocal 是Java类库的基础类,在包java.lang下

  • 详解Java中ThreadLocal类型及简单用法

    目录 1 基本概念 2 简单使用 3 应用场景 4 底层原理 4.1 set(Object) 4.2 get() 4.3 remove() 4.4 ThreadLocalMap 5 内存泄漏隐患和防止策略 5.1 为什么会发生内存泄漏? 5.2 怎样防止内存泄漏? 1 基本概念 ThreadLocal类提供了线程局部变量.这些变量与普通变量的不同之处在于,每个访问一个变量(通过其get或set方法)的线程都有自己的.独立初始化的变量副本.ThreadLocal实例通常是希望将状态与线程关联起来的

  • java 中模式匹配算法-KMP算法实例详解

    java 中模式匹配算法-KMP算法实例详解 朴素模式匹配算法的最大问题就是太低效了.于是三位前辈发表了一种KMP算法,其中三个字母分别是这三个人名的首字母大写. 简单的说,KMP算法的对于主串的当前位置不回溯.也就是说,如果主串某次比较时,当前下标为i,i之前的字符和子串对应的字符匹配,那么不要再像朴素算法那样将主串的下标回溯,比如主串为"abcababcabcabcabcabc",子串为"abcabx".第一次匹配的时候,主串1,2,3,4,5字符都和子串相应的

随机推荐