java中ThreadLocal使用

来源:互联网 发布:java类思维导图 编辑:程序博客网 时间:2024/04/28 02:04

什么是ThreadLocal?

顾名思义它是local variable(线程局部变量)。它的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。从线程的角度看,就好像每一个线程都完全拥有该变量。

使用场景

  1. To keep state with a thread (user-id, transaction-id, logging-id)
  2. To cache objects which you need frequently

ThreadLocal类

它主要由四个方法组成initialValue(),get(),set(T),remove(),其中值得注意的是initialValue(),该方法是一个protected的方法,显然是为了子类重写而特意实现的。该方法返回当前线程在该线程局部变量的初始值,这个方法是一个延迟调用方法,在一个线程第1次调用get()或者set(Object)时才执行,并且仅执行1次。ThreadLocal中的确实实现直接返回一个null:

ThreadLocal的原理

ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单,在ThreadLocal类中有一个Map,用于存储每一个线程的变量的副本。比如下面的示例实现:

public class ThreadLocal
{
 private Map values = Collections.synchronizedMap(new HashMap());
 public Object get()
 {
  Thread curThread = Thread.currentThread();
  Object o = values.get(curThread);
  if (o == null && !values.containsKey(curThread))
  {
   o = initialValue();
   values.put(curThread, o);
  }
  return o;
 }

 public void set(Object newValue)
 {
  values.put(Thread.currentThread(), newValue);
 }

 public Object initialValue()
 {
  return null;
 }
}

ThreadLocal 的使用

使用方法一:

Hibernate的文档时看到了关于使ThreadLocal管理多线程访问的部分。具体代码如下

1.  public static final ThreadLocal session = new ThreadLocal();
2.  public static Session currentSession() {
3.      Session s = (Session)session.get();
4.      //open a new session,if this session has none
5.   if(s == null){
6.      s = sessionFactory.openSession();
7.      session.set(s);
8.   }
      return s;
9. }

我们逐行分析
1。 初始化一个ThreadLocal对象,ThreadLocal有三个成员方法 get()、set()、initialvalue()。
    如果不初始化initialvalue,则initialvalue返回null。
3。session的get根据当前线程返回其对应的线程内部变量,也就是我们需要的net.sf.hibernate.Session(相当于对应每个数据库连接).多线程情况下共享数据库链接是不安全的。ThreadLocal保证了每个线程都有自己的s(数据库连接)。
5。如果是该线程初次访问,自然,s(数据库连接)会是null,接着创建一个Session,具体就是行6。
6。创建一个数据库连接实例 s
7。保存该数据库连接s到ThreadLocal中。
8。如果当前线程已经访问过数据库了,则从session中get()就可以获取该线程上次获取过的连接实例。

使用方法二

当要给线程初始化一个特殊值时,需要自己实现ThreadLocal的子类并重写该方法,通常使用一个内部匿名类对ThreadLocal进行子类化,EasyDBO中创建jdbc连接上下文就是这样做的:

public class JDBCContext{
private static Logger logger = Logger.getLogger(JDBCContext.class);
private DataSource ds;
protected Connection connection;
private boolean isValid = true;
private static ThreadLocal jdbcContext;

private JDBCContext(DataSource ds){
  this.ds = ds;
  createConnection(); 
}
public static JDBCContext getJdbcContext(javax.sql.DataSource ds)

  if(jdbcContext==null)jdbcContext=new JDBCContextThreadLocal(ds);
  JDBCContext context = (JDBCContext) jdbcContext.get();
  if (context == null) {
   context = new JDBCContext(ds);
  }
  return context;
}

private static class JDBCContextThreadLocal extends ThreadLocal {
  public javax.sql.DataSource ds;
  public JDBCContextThreadLocal(javax.sql.DataSource ds)
  {
   this.ds=ds;
  }
  protected synchronized Object initialValue() {
   return new JDBCContext(ds);
  }
}
}

使用单例模式,不同的线程调用getJdbcContext()获得自己的jdbcContext,都是通过JDBCContextThreadLocal 内置子类来获得JDBCContext对象的线程局部变量,这个

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 6个月宝宝咳嗽流鼻涕怎么办 18个月宝宝咳嗽流鼻涕怎么办 6个月宝宝流鼻涕打喷嚏怎么办 宝宝18个月流鼻涕怎么办 18个月宝宝感冒流鼻涕怎么办 小孩睡觉鼻子不通气怎么办 宝宝鼻子里有鼻涕出不来怎么办 孩子喉咙有痰呼呼响怎么办 六个月宝宝鼻塞怎么办速效办法 两个月小孩鼻子不通气怎么办 一岁宝宝流清鼻涕怎么办 孩子鼻子里有鼻涕怎么办 宝宝晚上睡觉鼻子不通气怎么办 宝宝感冒睡觉鼻子不通气怎么办 宝宝3个月流鼻涕怎么办 小孩吃着了发烧怎么办 半岁宝宝鼻子塞怎么办 宝宝伤风鼻子不通气怎么办 二十天的宝宝伤风鼻子不通怎么办 一个多月的宝宝鼻子有鼻屎怎么办 2个月宝宝鼻子里有鼻屎怎么办 四个月婴儿感冒发烧怎么办 一个月婴儿感冒发烧怎么办 五个月婴儿感冒发烧怎么办 两个月的婴儿感冒发烧怎么办 9个月婴儿感冒发烧怎么办 两个月婴儿感冒鼻塞咳嗽怎么办 两个月婴儿感冒咳嗽流鼻涕怎么办 小孩感冒发烧怎么办速效办法 宝宝打喷嚏流清鼻涕怎么办 宝宝感冒流清鼻涕怎么办 2岁感冒流清鼻涕怎么办 小孩感冒流清鼻涕怎么办 4岁宝宝半夜发烧怎么办 四岁宝宝免疫力低下怎么办 两岁宝宝咳嗽流鼻涕怎么办 小婴儿流清鼻涕怎么办 14个月宝宝流鼻涕怎么办 小孩一直流黄鼻涕怎么办 咳嗽有痰 浓鼻涕怎么办 儿童鼻窦炎总反复流脓鼻涕怎么办?