ThreadLocal及其扩展思路: SuperThreadLocal

210 阅读1分钟

1. ThreadLocal介绍

1. ThreadLocal用于为指定线程存取数据.源码介绍如下:

/**
 * This class provides thread-local variables.  These variables differ from
 * their normal counterparts in that each thread that accesses one (via its
 * {@code get} or {@code set} method) has its own, independently initialized
 * copy of the variable.

2. ThreadLocal提供了一种与众不同的线程安全方式,它不是在发生线程冲突时想办法解决冲突,而是彻底的避免了冲突的发生.ThreadLocal使用与原理

3. ThreadLocal使用方法/不熟悉百度下即可

  • ThreadLocal.set(T value)
  • ThreadLocal.get()
ThreadLocal<String> tl = new ThreadLocal<>();
//当前线程存储数据
tl.set("testStr");
//当前线程获取之前存储的数据
String getStr = tl.get();

/**
 * 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();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}
/**
 * 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) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    return setInitialValue();
}

2. ThreadLocal的问题: 只能存储1个数据. set-->get.

如何扩展: 可以存储多个数据,存储成Map的形式. 采用和ThreadLocal类似的思路,数据和指定线程绑定,实现数据隔离.

3. ThreadLocal扩展具体实现 -> SuperThreadLocal

临时想到的一个扩展的ThreadLocal工具类,备忘.

import java.lang.ref.WeakReference;
import java.util.HashMap;

public class SuperThreadLocal {
	private static HashMap<SuperWeakReference, HashMap<String, Object>> map = new HashMap<SuperWeakReference, HashMap<String, Object>>();
	public synchronized static void set(String key,Object value){
		SuperWeakReference superWeakReference = new SuperWeakReference(Thread.currentThread());
		if(containsKey(superWeakReference)){
			getKeyValue(superWeakReference).put(key, value);
		}else{
			HashMap<String, Object> realKeyValue = new HashMap<String, Object>();
			realKeyValue.put(key, value);
			map.put(superWeakReference, realKeyValue);
		}
	}
	public synchronized static Object get(String key){
		SuperWeakReference superWeakReference = new SuperWeakReference(Thread.currentThread());
		if(containsKey(superWeakReference)){
			return getKeyValue(superWeakReference).get(key);
		}else{
			return null;
		}
	}
	
	private static HashMap<String, Object> getKeyValue(SuperWeakReference superWeakReference){
		return map.get(superWeakReference);
	} 
	private static boolean containsKey(SuperWeakReference superWeakReference){
		return map.containsKey(superWeakReference);
	}
	static class SuperWeakReference extends WeakReference<Thread>{
		private Thread currThread;
		public SuperWeakReference(Thread referent) {
			super(referent);
			this.currThread = referent;
		}
		@Override
		public boolean equals(Object obj) {
		    if(obj == this){
		    	return true;
		    }else if(obj == null){
				return false;
			}else if(!(obj instanceof SuperWeakReference)){
				return false;
			}else{
				SuperWeakReference ori = (SuperWeakReference) obj;
				return ori.get() != null && ori.get() == currThread;
			}
		}
		@Override
		public int hashCode() {
			return (int) (currThread == null ? -1L : currThread.getId());
		}
	}
}