JAVA

ThreadLocal 浅析

2017-12-24  本文已影响5人  清风徐来水波不清

ThreadLocal是什么?

早在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。
java.lang.ThreadLocal提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其 get 或 set 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal 实例通常是类中的 private static 字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联。
每个线程都保持对其线程局部变量副本的隐式引用,只要线程是活动的并且 ThreadLocal 实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被GC回收(除非存在对这些副本的其他引用)。

ThreadLocal接口方法

   public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
 protected T initialValue() {
       return null;
   }
       Thread t = Thread.currentThread();
       ThreadLocalMap map = getMap(t);
       if (map != null) {
           ThreadLocalMap.Entry e = map.getEntry(this);
           if (e != null)
               return (T)e.value;
       }
       return setInitialValue();
   }
  public void remove() {
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
             m.remove(this);
     }

源码浅析

也许我们分析JDK中的源码有些难以理解,我们可以将ThreadLocal类简化一下,简化后的代码如下

class MyThreadLocal<T>{
private Map<Thread,T> map = new HashMap<Thread,T>();
     protected T initialValue() {
        return null;
    }
  
  public void set(T value) {
        map.put(Thread.currentThread(), value);
    }
    
    public void remove() {
        map.remove(Thread.currentThread());
    }
    
    public T get() {
        return map.get(Thread.currentThread());
    }
}

其实在ThreadLocal内部是维护了一个Map来保存数据的,虽然使用的时候获取的是value值,但是其每一个value对应的key都是当前线程,因此相当于将变量给每一个线程复制了一份,各个线程对数据的操作不会互相影响.

实用案例

我们在对数据库进行操作的时候有时候为了数据安全必须加事务操作,但是一般事务管理在Service层,而数据操作在DAO层,一般的做法就是在Service层建立连接然后传参的形式传递给DAO层,这无疑增加了程序的侵入性,其实在Spring的事务管理底层就使用了ThreadLocal来解决这种情况,我们也可以模拟使用ThreadLocal编写一个带有事务操作工具类.

public class JdbcUtils {
    private static DataSource dataSource = new ComboPooledDataSource();
    private static ThreadLocal<Connection> tl  = new ThreadLocal<Connection>();
  //获取数据源
    public static DataSource getDataSource() {
        return dataSource;
    }
  //获取连接
    public static Connection getConnection() throws SQLException {
        Connection con = tl.get(); 
        if(con == null) {
            return dataSource.getConnection();
        }
        return con;
    }
    //开始事务
    public static void beginTranscation() throws SQLException {
        Connection con = tl.get(); 
        if(con != null ) {
            throw new SQLException("事务已经开启,在没有结束当前事务时,不能再开启事务!");
        }
        con = dataSource.getConnection(); 
        con.setAutoCommit(false); 
        tl.set(con); 
    }
    //提交事务
    public static void commitTransaction() throws SQLException {
        Connection con = tl.get(); 
        if(con == null ) {
            throw new SQLException("当前没有事务,所以不能提交事务!");
        }
        con.commit(); 
        con.close(); 
        tl.remove(); 
    }
    // 回滚事务
    public static void rollbackTransaction() throws SQLException {
        Connection con = tl.get();
        if(con == null) {
            throw new SQLException("当前没有事务,所以不能回滚事务!");
        }
        con.rollback();
        con.close();
        tl.remove();
    }
}

上一篇下一篇

猜你喜欢

热点阅读