ThreadLocal
对于多任务,Java 标准库提供的线程池可以方便地执行这些任务,同时复用线程。那么如何在一个线程内传递状态?
如下栗子,一个内部需要调用若干其他方法,同时传递参数 user。
这种在一个线程中,横跨若干方法调用,需要传递的对象,我们通常称之为上下文(Context),它是一种状态,可以是用户身份、任务信息等。
给每个方法增加一个 context 参数非常麻烦,而且有些时候,如果调用链有无法修改源码的第三方库,User 对象就传不进去了。
Java 标准库提供了一个特殊的 ThreadLocal
,它可以在一个线程中传递同一个对象。
ThreadLocal
实例通常总是以静态字段初始化如下:
使用方式:
注意到普通的方法调用一定是同一个线程执行的,所以,step1()
、step2()
方法内,threadLocalUser.get()
获取的 User 对象是同一个实例。
实际上,可以把 ThreadLocal
看成一个全局 Map<Thread, Object>
,每个线程获取 ThreadLocal
变量时,总是使用 Thread 自身作为 key:
因此,ThreadLocal
相当于给每个线程都开辟了一个独立的存储空间,各个线程的 ThreadLocal
关联的实例互不干扰。
最后,特别注意 ThreadLocal 一定要在 finally 中清除。这是因为当前线程执行完相关代码后,很可能会被重新放入线程池中,如果 ThreadLocal
没有被清除,该线程执行其他代码时,会把上一次的状态带进去。
为了保证能释放 ThreadLocal
关联的实例,我们可以通过 AutoCloseable
接口配合 try (resource) {...}
结构,让编译器自动为我们关闭。例如,一个保存了当前用户名的 ThreadLocal
可以封装为一个 UserContext
对象:
使用方式:
这样就在 UserContext
中完全封装了 ThreadLocal
,外部代码在 try (resource) {...}
内部可以随时调用 UserContext.currentUser()
获取当前线程绑定的用户名。
小结
ThreadLocal
空间换时间,synchronized
时间换空间。
ThreadLocal
表示线程的“局部变量”,它确保每个线程的ThreadLocal
变量都是各自独立的;ThreadLocal
适合在一个线程的处理流程中保持上下文(避免了同一参数在所有方法中传递);- 使用
ThreadLocal
要用try ... finally
结构,并在finally
中清除。
DEMO
ThreadLocal SimpleDateFormat
金点网络-全网资源,一网打尽 » Java 并发编程·ThreadLocal
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。
- 是否提供免费更新服务?
- 持续更新,永久免费
- 是否经过安全检测?
- 安全无毒,放心食用