java 线程变量put_Java线程(篇外篇):线程本地变量ThreadLocal

本文介绍了Java中的ThreadLocal类,它用于线程内共享数据,避免参数传递。文章详细阐述了ThreadLocal的工作原理,包括get、set、remove方法的实现,并澄清了一些常见误解。通过示例代码展示了如何使用ThreadLocal管理数据库连接,强调了统一管理和降低耦合性的优点。
摘要由CSDN通过智能技术生成

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

/**

* 数据库连接管理类

* @author 爽

*

*/

public class ConnectionManager {

/** 线程内共享Connection,ThreadLocal通常是全局的,支持泛型 */

private static ThreadLocal threadLocal = new ThreadLocal();

public static Connection getCurrConnection() {

// 获取当前线程内共享的Connection

Connection conn = threadLocal.get();

try {

// 判断连接是否可用

if(conn == null || conn.isClosed()) {

// 创建新的Connection赋值给conn(略)

// 保存Connection

threadLocal.set(conn);

}

} catch (SQLException e) {

// 异常处理

}

return conn;

}

/**

* 关闭当前数据库连接

*/

public static void close() {

// 获取当前线程内共享的Connection

Connection conn = threadLocal.get();

try {

// 判断是否已经关闭

if(conn != null && !conn.isClosed()) {

// 关闭资源

conn.close();

// 移除Connection

threadLocal.remove();

conn = null;

}

} catch (SQLException e) {

// 异常处理

}

}

}

这样处理的好处:

统一管理Connection;

不需要显示传参Connection,代码更优雅;

降低耦合性。

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方法:

/**

* Sets the current thread's copy of this thread-local variable

* to the specified value.  Most subclasses will have no need to

* override this method, relying solely on the {@link #initialValue}

* method to set the values of thread-locals.

*

* @param value the value to be stored in the current thread's copy of

*        this thread-local.

*/

public void set(T value) {

// 获取当前线程对象

Thread t = Thread.currentThread();

// 获取当前线程本地变量Map

ThreadLocalMap map = getMap(t);

// map不为空

if (map != null)

// 存值

map.set(this, value);

else

// 创建一个当前线程本地变量Map

createMap(t, value);

}

/**

* Get the map associated with a ThreadLocal. Overridden in

* InheritableThreadLocal.

*

* @param  t the current thread

* @return the map

*/

ThreadLocalMap getMap(Thread t) {

// 获取当前线程的本地变量Map

return t.threadLocals;

}

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

get方法:

/**

* Returns the value in the current thread's copy of this

* thread-local variable.  If the variable has no value for the

* current thread, it is first initialized to the value returned

* by an invocation of the {@link #initialValue} method.

*

* @return the current thread's value of this thread-local

*/

public T get() {

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();

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

(完)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值