前言
在日常的开发中,我们经常会遇到在当前运行线程中保存一些信息,并且各线程之间是隔离的,不会相互影响,不存在并发问题,通过这样的方式来实现请求调用链中方法之间参数传递的解耦,提升代码结构的稳定性等。java ThreadLocal就是用于实现这一目标的。
实现原理
要理解ThreadLocal的实现原理,必须理解以下三个类:
- Thread
- ThreadLocal
- ThreadLocalMap(ThreadLocal的静态内部类)
实现原理图:
1.在每个Thread线程内部,有一个包内可见的ThreadLocalMap实例,用于存储线程内信息public class Thread implements Runnable {
/* ThreadLocal values pertaining to this thread. This map is maintained by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
}
2.ThreadLocal类部分代码public class ThreadLocal<T> {
/**
* 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();
}
/**
* Get the map associated with a ThreadLocal. Overridden in
* InheritableThreadLocal.
* @param t the current thread
* @return the map
*/
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
/**
* Variant of set() to establish initialValue. Used instead
* of set() in case user has overridden the set() method.
* @return the initial value
*/
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
/**
* Create the map associated with a ThreadLocal. Overridden in
* InheritableThreadLocal.
* @param t the current thread
* @param firstValue value for the initial entry of the map
* @param map the map to store.
*/
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
}
3.ThreadLocalMap是ThreadLocal的一个静态内部类,是一个Map结构,key为ThreadLocal类型,value为Object类型【Map static class ThreadLocalMap {
/**
* The entries in this hash map extend WeakReference, using
* its main ref field as the key (which is always a
* ThreadLocal object). Note that null keys (i.e. entry.get()
* == null) mean that the key is no longer referenced, so the
* entry can be expunged from table. Such entries are referred to
* as "stale entries" in the code that follows.
*/
static class Entry extends WeakReference<ThreadLocal> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal k, Object v) {
super(k);
value = v;
}
}
private static final int INITIAL_CAPACITY = 16;
/**
* The table, resized as necessary.
* table.length MUST always be a power of two.
*/
private Entry[] table;
}
}
}
使用示例
通过使用ThreadLocal实现线程上下文管理器功能,示例代码如下:
线程上下文管理器:ThreadContextManager/** 功能描述:线程上下文管理器 */
public class ThreadContextManager
{
//可以针对不同的业务场景,定义多个ThreadLocal对象
private static ThreadLocal<ThreadContext> contextMap = null;
static
{
init();
}
private static void init()
{
contextMap = new ThreadLocal<ThreadContext>();
}
public static ThreadContext getThreadContext()
{
return contextMap.get();
}
/** 获取初始化的线程上下文
* @return
*/
public static ThreadContext getInitThreadContext()
{
ThreadContext threadContext = contextMap.get();
// 享元模式:达到对对象的复用,降低对象的创建及销毁所带来的开销
if (threadContext != null)
{
threadContext.init();
}
else
{
threadContext = new ThreadContext();
contextMap.set(threadContext);
}
return threadContext;
}
线程上下文:ThreadContextpublic class ThreadContext implements Serializable {
private static final long serialVersionUID = 1L;
//线程上下文扩展属性存放Map
private Map<String, Object> data = null;
//当前请求链中的Request对象,参数隐式传递
private HttpServletRequest request = null;
//当前请求链中的Response对象,参数隐式传递
private HttpServletResponse response = null;
public ThreadContext() {
data = new HashMap<String, Object>();
}
public Map<String, Object> getData() {
return data;
}
public void setData(Map<String, Object> data) {
this.data = data;
}
public HttpServletRequest getRequest() {
return request;
}
public ThreadContext setRequest(HttpServletRequest request) {
this.request = request;
return this;
}
public HttpServletResponse getResponse() {
return response;
}
public ThreadContext setResponse(HttpServletResponse response) {
this.response = response;
return this;
}
public Object getValue(String key) {
return data.get(key);
}
public ThreadContext setValue(String key, Object value) {
if (StringUtils.isEmpty(key)) { throw new IllegalArgumentException("key is blank"); }
data.put(key, value);
return this;
}
public HttpSession getSession() {
return request.getSession();
}
// 初始化该上下文,达到对象的复用
public void init() {
data = new HashMap<String, Object>();
request = null;
response = null;
}
在web开发中,具体使用该线程上下文管理器:
框架级过滤器: ApplicationFilter//功能描述:框架级过滤器
public class ApplicationFilter implements Filter {
private static final String DEFAULT_ENCODING = "UTF-8";
private String charset = null;
public void init(FilterConfig filterConfig) throws ServletException {
charset = filterConfig.getInitParameter("encoding");
if (StringUtils.isBlank(charset)) {
charset = DEFAULT_ENCODING;
}
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException {
// 设置请求及响应编码
request.setCharacterEncoding(charset);
response.setCharacterEncoding(charset);
// 设置线程上下文
ThreadContextManager.getInitThreadContext().setRequest((HttpServletRequest) request).setResponse((HttpServletResponse) response);
chain.doFilter(request, response);
}
public void destroy() {}
}
控制器基类:BaseController/**
* 功能描述:基础控制器抽象类
*/
public abstract class BaseController {
/**
* 获取请求对象
* @return
*/
public HttpServletRequest getRequest() {
return ThreadContextManager.getThreadContext().getRequest();
}
/**
* 获取响应对象
* @return
*/
public HttpServletResponse getResponse() {
return ThreadContextManager.getThreadContext().getResponse();
}
/**
* 获取当前会话
* @return
*/
public HttpSession getSession() {
return ThreadContextManager.getThreadContext().getSession();
}
}
使用场景
- 参数隐式传递
- 请求调用链中信息存储 - 例如(线程调用方法的方法,耗时,错误等信息)