ThreadLocal - 基础

ThreadLocal:java.lang.ThreadLocal
	应用:应用在同一个线程的不同开发层次中共享数据。例如:Struts2中的ActionContext、Spring中管理数据库的连接、Hibernate中的Session
	实现:
		1)建立一个类,并在其中封装一个静态的ThreadLocal变量,使其成为一个共享的数据环境。
		2)在类中实现访问静态ThreadLocal变量的静态方法(设值和取值)

	【说明】:ThreadLocal通过操作当前线程中的一个内部变量(ThreadLocalMap)来达到与其它线程隔离的目的。
		1)ThreadLocalMap变量属于线程的内部属性,不同的线程拥有完全不同的ThreadLocalMap变量
		2)线程中的ThreadLocalMap变量的值是在ThreadLocal对象进行set或get操作时创建的,在创建之前会检查当前线程中的ThreadLocalMap是否为null,如果为null则创建,如果不为null,则使用已经存在的ThreadLocalMap
		3)使用当前线程的ThreadLocalMap的关键在于:使用当前的ThreadLocal的实例作为key进行储存
	【重要】:
		1)一个ThreadLocal只能储存一个变量,如果重复调用ThreadLocal的set方法,则新值会将旧值覆盖。
		2)如果需要在一个线程中共享多个变量,则可以将多个变量封装到一个对象中,然后将该对象存储在ThreadLocal中。Struts2中的ActionContext就是这样设计的。
		3)在ThreadLocalMap中,如果当前线程中定义了多个不同的ThreadLocal的实例,则它们会作为不同的key进行储存而不会相互干扰!


	java.lang.Thread的部分源码:
		public class Thread implements Runnable {
			//这里省略了许多其它的代码
			
			ThreadLocal.ThreadLocalMap threadLocals = null;
		}
		
	java.lang.ThreadLocal的部分源码:
		public Class ThreadLocal<T> {

			//这里省略了许多其它的代码


		    /**
		     * ThreadLocalMap is a customized hash map suitable only for maintaining thread local values.
		     * No operations are exported outside of the ThreadLocal class.
		     * The class is package private to allow declaration of fields in class Thread.
		     * 
		     * # 用于处理生命周期很长的场景,hash表中entry的key被弱引用。
		     * To help deal with very large and long-lived usages, the hash table entries use WeakReferences for keys.
		     * 
		     * However, since reference queues are not used, stale entries are guaranteed to be removed only when the table starts running out of space.
		     */
		    static class ThreadLocalMap {

		        /**
		         * Entry继承了弱引用
		         */
		        static class Entry extends WeakReference<ThreadLocal<?>> {
                    
                    // private T referent; // Entry继承了WeakReference的referent属性。	            

		            Object value;

                    // 堆内存中的threadlocal对象k,被Entry对象弱引用。Entry对象通过referent属性引用着threadlocal对象k
		            Entry(ThreadLocal<?> k, Object v) {
		                super(k);
		                value = v;
		            }
		        }

		        /**
		         * Set the value associated with key.
		         *
		         * @param key the thread local object
		         * @param value the value to be set
		         */
		        private void set(ThreadLocal<?> key, Object value) {

		            Entry[] tab = table;
		            int len = tab.length;
		            int i = key.threadLocalHashCode & (len-1);

		            for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) {
		                ThreadLocal<?> k = e.get();

		                if (k == key) {
		                    e.value = value;
		                    return;
		                }

		                if (k == null) {
		                    replaceStaleEntry(key, value, i);
		                    return;
		                }
		            }

		            // key被弱引用
		            tab[i] = new Entry(key, value);

		            int sz = ++size;
		            if (!cleanSomeSlots(i, sz) && sz >= threshold) rehash();
		        }
		    }
			

			// 将value的值保存在当前线程的本地变量表(ThreadLocalMap)中
			public void set(T value){
				// 获取当前线程
				Thread t = Thread.currentThread();
				// 调用getMap方法获得当前线程中的本地变量表ThreadLocalMap
				ThreadLocalMap map = getMap(t);
				// 如果本地变量表ThreadLocalMap已经存在,则直接使用
				if (map != null){
					// 以当前的ThreadLocal的实例作为key,储存在当前线程中。ThreadLocalMap
					// ThreadLocalMap中,如果当前线程中定义了多个不同的ThreadLocal的实例,则它们会作为不同的key进行储存而不会相互干扰
					// ThreadLocalMap的set方法:private void set(ThreadLocal<?> key, Object value)
					map.set(this, value);
				} else {
					// 如果ThreadLocalMap不存在,则初始化map
					createMap(t, value);
				}	
			}

			
			// 获取当前线程中以当前ThreadLocal实例为key的变量值
			public T get() {
				// 获取当前线程
				Thread t = Thread.currentThread();
				// 获取当前线程中的ThreadLocalMap
				ThreadLocalMap map = getMap(t);
				if (map != null) {
					// 获取当前线程中以当前ThreadLocal实例为key的变量值
					ThreadLocalMap.Entry e = map.getEntry(this);
					if (e != null) {
						return (T)e.value;
					}
				}
				
				// 当map不存在时,初始化map,并返回null
				return setInitialValue();
			}
			
			// 从当前线程中获取与之对应的ThreadLocalMap
			ThreadLocalMap getMap(Thread t) {
				return t.threadlocals;
			}
			
			// 创建当前线程中的ThreadLocalMap
			void createMap(Thread t, T firstValue) {
				// 调用构造函数生成当前线程中的ThreadLocalMap
				t.threadLocals = new ThreadLocalMap(this, firstValue);
			}
			
			// 初始化当前线程的ThreadLocalMap
			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;
			}
			
			// 若当前线程的ThreadLocalMap不存在时,调用ThreadLocal的get()方法默认返回null。
			// 若子类覆盖父类ThreadLocal的该方法,则可以设置当(当前线程的)ThreadLocalMap不存在时,get()方法默认返回的值。
			protected T initialValue() {
				return null;
			}

			
			// ThreadLocalMap的定义 
			static class ThreadLocalMap{
				// ...
			}
			
		}


	应用举例:Struts2中的ActionContext
		
	ActionContext在内部封装了一个静态的ThreadLocal的实例,而这一实例操作的对象()又是ActionContext本身。
		
	Struts2中的ActionContext的部分源码:	
		public class ActionContext implements Serializable {
			// 此处省略了很多代码
			
			// 封装了一个ThreadLocal变量,储存的内容是ActionContext本身
			static ThreadLocal actionContext = new ThreadLocal();
			
			// 在ThreadLocal中设置ActionContext,绑定到当前线程。
			public static void setContext(ActionContext context){
				actionContext.set(context);
				// 注:ThreadLocal的set方法调用了ThreadLocalMap(当前线程的本地变量表)的set(threadLocal, value)方法:以当前的ThreadLocal的实例作为key,储存在当前线程的ThreadLocalMap属性中
			}
			
			// 返回当前线程中储存的ActionContext
			public static ActionContext getContext(){
				// 返回当前线程中储存的ActionContext
				return (ActionContext) actionContext.get();
			}
			
		}



	

ThreadLocal - 内存泄露_threadlocal 内存泄漏-CSDN博客

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值