简析ThreadLocal

来源:互联网 发布:农村淘宝app下载安装 编辑:程序博客网 时间:2024/06/17 08:57

前言

对于ThreadLocal这个类,很多小伙伴可能见的不多,或者说见过,但是没有注意过这个无关痛痒的小玩意。在日常的增删改查中好像也没有用到这个类啊,那么这个类到底有什么用呢??下面来和大家一起总结一下。

ThreadLocal中的四个方法

ThreadLocal是在jdk1.2中引入的一个类,看到这个名字。大家也估计猜到是和线程有所关联,根据字面意思翻译过来是,线程局部??这好像也不通啊,其实我们可以理解为线程局部变量,这么这个类有啥用呢。ThreadLocal是为一个成员变量在每个线程之中提供一个副本,使得各个线程之间对于某一成员变量的调用不相互干扰,说到这里大家可能理解更清楚一点了。但是对于多线程有所了解的同学,肯定会将上面的那段话和多线程实现线程安全混淆在一起。在多线程同步中,是采用加锁的方式来实现同一时间只能有唯一一个线程来访问修改各个线程共享的变量。这样就可以维持各个线程对于同一变量调用的是一致性。有人将ThreadLocal理解为,是用空间来换取时间,这样获取效率上的提高,对于线程同步,是用时间来换取空间。但是需要理解的一点,他们本质用途不是一样的。线程的目的是控制对共享变量的访问,但是ThreadLocal的目的是隔离各个线程之间的变量,这个变量是不需要在各个线程之间共享的。他们是在各个线程之中创建了属于自己的变量,同时将这个变量和自己的线程对象进行绑定。
接下来,我们先看看ThreadLocal中四个常用的方法。
1. void set(Object value)
设置当前线程的线程局部变量的值
2. public Object get()
该方法返回当前线程所对应的线程局部变量。
3. public void remove()
将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。
4. protected Object initialValue()
返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()或set(Object)时才执行,并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null。
上面说到ThreadLocal是对每个线程提供一个单独的副本,那么他是怎么维持各个线程的副本的呢?其实,ThreadLocal中有一个Map,这个map的Key存储的是当前线程的对象Thread.currentThread(),value中存储的是线程中的副本。那么这个map在ThreadLocal扮演什么的角色呢,可以结合下面的小例子看一看。

public class SimpleThreadLocal {    private Map valueMap = Collections.synchronizedMap(new HashMap());    public void set(Object newValue) {    valueMap.put(Thread.currentThread(), newValue);//键为线程对象,值为本线程的变量副本    }    public Object get() {    Thread currentThread = Thread.currentThread();    Object o = valueMap.get(currentThread);//返回本线程对应的变量    if (o == null && !valueMap.containsKey(currentThread)) {    //如果在Map中不存在,放到Map中保存起来。    o = initialValue();    valueMap.put(currentThread, o);    }    return o;    }    public void remove() {    valueMap.remove(Thread.currentThread());    }    public Object initialValue() {    return null;    }}

综上所示,以上就是关于ThreadLocal中的四个方法的介绍。

Hibernate中的小例子

在上面对于ThreadLocal中的四个方法介绍之后,相必大家已经清楚了ThreadLocal的原理了。这里再结合Hibernate中线程安全的session来讲解一下ThreadLocal在Hibernate中创建线程安全中的session。其实在Hibernate中,session就是和线程进行绑定的。这样才不会影响其他各个线程。具体可以结合下面的代码进行查看。

public class HibernateUtil {    private static SessionFactory factory;    // 使用ThreadLocal集合保存当前业务线程中的SESSION    private static ThreadLocal session = new ThreadLocal();    static {        // 第一步:读取HIBERNATE的配置文件,读取hibernate.cfg.xml文件        Configuration con = new Configuration().configure();        // 第二步:创建服务注册构建器对象,通过配置对象中加载所有的配置信息,存放到注册服务中        ServiceRegistryBuilder regBuilder = new ServiceRegistryBuilder()                .applySettings(con.getProperties());        // 创建注册服务        ServiceRegistry reg = regBuilder.buildServiceRegistry();        // 第三步:创建会话工厂        factory = con.buildSessionFactory(reg);    }    public static Session getLocalThreadSession() {        Session s = session.get();// 获取当前线程下的Session        if (s == null) {            s = getFactory().getCurrentSession();// 获取当前线程中的Session            session.set(s);// 将当前Session放入到当前线程的容器中保存        }        return s;    }    public static void closeSession() {        Session s = session.get();// 获取当前线程下的Session        if (s != null) {            session.set(null);// 将当前线程中的会话清除        }    }}

上面的小例子,就是简述了Hibernate中session如何实现各个线程之间的隔离。

总结

上面就是对于ThreadLocal的一点小总结。小知识,也不要掉以轻心哦!一天一个小贝壳,总有一天你会发现原来你已拥有整片海滩!

原创粉丝点击