0
点赞
收藏
分享

微信扫一扫

Java线程外篇:线程本地变量ThreadLocal


 首先说明ThreadLocal存放的值是线程内共享的,线程间互斥的,主要用于线程内共享一些数据,避免通过参数来传递,这样处理后,能够优雅的解决一些实际问题,比如Hibernate中的OpenSessionInView,就是使用ThreadLocal保存Session对象,还有我们经常用ThreadLocal存放Connection,代码如:


[java]  ​​view plain​​ ​​copy​​ ​​print​​ ​​?​​



  1. /**
  2.  * 数据库连接管理类
  3.  * @author 爽
  4.  *
  5.  */  
  6. public class ConnectionManager {  
  7.   
  8. /** 线程内共享Connection,ThreadLocal通常是全局的,支持泛型 */  
  9. private static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();  
  10.       
  11. public static Connection getCurrConnection() {  
  12. // 获取当前线程内共享的Connection  
  13.         Connection conn = threadLocal.get();  
  14. try {  
  15. // 判断连接是否可用  
  16. if(conn == null || conn.isClosed()) {  
  17. // 创建新的Connection赋值给conn(略)  
  18. // 保存Connection  
  19.                 threadLocal.set(conn);  
  20.             }  
  21. catch (SQLException e) {  
  22. // 异常处理  
  23.         }  
  24. return conn;  
  25.     }  
  26.       
  27. /**
  28.      * 关闭当前数据库连接
  29.      */  
  30. public static void close() {  
  31. // 获取当前线程内共享的Connection  
  32.         Connection conn = threadLocal.get();  
  33. try {  
  34. // 判断是否已经关闭  
  35. if(conn != null && !conn.isClosed()) {  
  36. // 关闭资源  
  37.                 conn.close();  
  38. // 移除Connection  
  39.                 threadLocal.remove();  
  40. null;  
  41.             }  
  42. catch (SQLException e) {  
  43. // 异常处理  
  44.         }  
  45.     }  
  46. }  


       这样处理的好处:

  1. 统一管理Connection;
  2. 不需要显示传参Connection,代码更优雅;
  3. 降低耦合性。

       ThreadLocal有四个方法,分别为:

initialValue


protected ​​T​​ initialValue()


返回此线程局部变量的当前线程的初始值。最多在每次访问线程来获得每个线程局部变量时调用此方法一次,即线程第一次使用  ​​get()​​ 方法访问变量的时候。如果线程先于 

get 方法调用  ​​set(T)​​ 方法,则不会在线程中再调用 

initialValue 方法。

null;如果程序员希望将线程局部变量初始化为 null 以外的某个值,则必须为 ThreadLocal 创建子类,并重写此方法。通常,将使用匿名内部类。initialValue


返回:

返回此线程局部变量的初始值


get


public ​​T​​ get()



返回:

此线程局部变量的当前线程的值


set


public void set(​​T​​ value)


将此线程局部变量的当前线程副本中的值设置为指定值。许多应用程序不需要这项功能,它们只依赖于  ​​initialValue()​​ 方法来设置线程局部变量的值。



参数:

​value​​ - 存储在此线程局部变量的当前线程副本中的值。



remove


public void remove()


initialValue。

       很多人对ThreadLocal存在一定的误解,说ThreadLocal中有一个全局的Map,set时执行map.put(Thread.currentThread(), value),get和remove时也同理,但SUN的大师们是否是如此实现的,我们只能去看源码了。

       set方法:


[java]  ​​view plain​​ ​​copy​​ ​​print​​ ​​?​​



  1. /**
  2.  * Sets the current thread's copy of this thread-local variable
  3.  * to the specified value.  Most subclasses will have no need to
  4.  * override this method, relying solely on the {@link #initialValue}
  5.  * method to set the values of thread-locals.
  6.  *
  7.  * @param value the value to be stored in the current thread's copy of
  8.  *        this thread-local.
  9.  */  
  10. public void set(T value) {  
  11. // 获取当前线程对象  
  12.     Thread t = Thread.currentThread();  
  13. // 获取当前线程本地变量Map  
  14.     ThreadLocalMap map = getMap(t);  
  15. // map不为空  
  16. if (map != null)  
  17. // 存值  
  18. this, value);  
  19. else  
  20. // 创建一个当前线程本地变量Map  
  21.         createMap(t, value);  
  22. }  
  23.   
  24. /**
  25.  * Get the map associated with a ThreadLocal. Overridden in
  26.  * InheritableThreadLocal.
  27.  *
  28.  * @param  t the current thread
  29.  * @return the map
  30.  */  
  31. ThreadLocalMap getMap(Thread t) {  
  32. // 获取当前线程的本地变量Map  
  33. return t.threadLocals;  
  34. }  


       这里注意,ThreadLocal中是有一个Map,但这个Map不是我们平时使用的Map,而是ThreadLocalMap,ThreadLocalMap是ThreadLocal的一个内部类,不对外使用的。当使用ThreadLocal存值时,首先是获取到当前线程对象,然后获取到当前线程本地变量Map,最后将当前使用的ThreadLocal和传入的值放到Map中,也就是说ThreadLocalMap中存的值是[ThreadLocal对象, 存放的值],这样做的好处是,每个线程都对应一个本地变量的Map,所以一个线程可以存在多个线程本地变量

       get方法:


[java]  ​​view plain​​ ​​copy​​ ​​print​​ ​​?​​



  1. /**
  2.  * Returns the value in the current thread's copy of this
  3.  * thread-local variable.  If the variable has no value for the
  4.  * current thread, it is first initialized to the value returned
  5.  * by an invocation of the {@link #initialValue} method.
  6.  *
  7.  * @return the current thread's value of this thread-local
  8.  */  
  9. public T get() {  
  10.     Thread t = Thread.currentThread();  
  11.     ThreadLocalMap map = getMap(t);  
  12. if (map != null) {  
  13. this);  
  14. if (e != null)  
  15. return (T)e.value;  
  16.     }  
  17. // 如果值为空,则返回初始值  
  18. return setInitialValue();  
  19. }  


       有了之前set方法的分析,get方法也同理,需要说明的是,如果没有进行过set操作,那从ThreadLocalMap中拿到的值就是null,这时get方法会返回初始值,也就是调用initialValue()方法,ThreadLocal中这个方法默认返回null。当我们有需要第一次get时就能得到一个值时,可以继承ThreadLocal,并且覆盖initialValue()方法。

举报

相关推荐

0 条评论