项目中,如果某个对象是线程不安全的,在多线程环境下,对对象必须要采用synchronized加锁来进行线程同步。但是这样来解决线程安全的问题,会带来很大的性能损失。如果在获取数据库connection对象时,使用加锁来解决各个connection对象之间的线程安全问题。那么用户访问时,一个线程在使用数据库操作,而其他线程的connection对象只能串行等待,这样会严重影响性能问题。 为了更好地处理解决这种问题,java中提供了java.lang.ThreadLocal这个类来实现多线程访问对象的解决方案。ThreadLocal的主要应用场景为按线程多实例(每个线程对应一个实例)的对象的访问,并且这个对象很多地方都要用到。 ThreadLocal官网解释: This class provides thread-localvariables. These variables differ fromtheir normalcounterparts in that eachthread that accesses one (via its {@code get} or {@code set} method) has its own, independently initialized copy of the variable. {@code ThreadLocal} instances are typically privatestatic fields in classes that wish toassociate state with a thread (e.g.,a user ID or Transaction ID). ThreadLocal类用来提供线程内部的局部变量。这些变量在多线程环境下访问(通过get或set方法访问)时能保证各个线程里的变量相对独立于其他线程内的变量,ThreadLocal实例通常来说都是private static类型。 ThreadLocal不是为了解决多线程访问共享变量,而是为每个线程创建一个单独的变量副本,提供了保持对象的方法和避免参数传递的复杂性。 在Spring,Hibernate,Struts2中对于ThreadLocal都有广泛的应用,在Hibernate中获取connection也是通过ThreadLocal来封装connection对象,实现了连接connection之间不会相互影响的效果。在Struts2中通过ThreadLocal来封装每个请求,让每个用户的request请求分离达到不同用户线程之间获取不同的request对象效果。 ThreadLocal原理 ThreadLocal可以看做是一个容器,容器里面存放着属于当前线程的变量。使用一个Map来把线程作为key,对象作为value来存储对象,这样能上达到各个线程能够存储一个对象,让每个线程的对象独立分割开来的效果。 对于ThreadLocal的基本原理,atv直播,我们可以提供一个基本模拟版本给大家参考。 publicclassSimpleThreadLocal { privateMap valueMap = Collections.synchronizedMap(newHashMap()); publicvoidset(Object newValue) { //键为线程对象,值为本线程的变量副本 valueMap.put(Thread.currentThread(), newValue); } publicObject get() { Thread currentThread = Thread.currentThread(); //返回本线程对应的变量 Object o = valueMap.get(currentThread); //如果在Map中不存在,放到Map中保存起来 if(o == null&& !valueMap.containsKey(currentThread)) { o = initialValue(); valueMap.put(currentThread, o); } returno; } publicvoidremove() { valueMap.remove(Thread.currentThread()); } publicObject initialValue() { returnnull; } } SimpleThreadLocal 一共提供了4个方法 void set(Object newValue):根据当前线程,来设置当前线程的对象值, Object get():获取当前线程的对象 void remove():删除当前线程里的对象 initialValue():设置当前对象的默认初始值 ThreadLocal源码 以下是JDK1.5中的TheadLocal部分源码: 可以看到,源码中的方法与我们上述模拟的ThreadLocal简单版本一致。而在方法内部做了一些更加复杂的控制。 (责任编辑:本港台直播) |