ThreadLocal 多线程中对象引用的理解

这次的博客带来的是关于ThreadLocal<T>的理解

什么是ThreadLocal呢?根据名称来看,ThreadLocal即线程本地的意思。另外它还是一个范型类,这个范型T,就是threadLocal.set(T)的参数,也是threadLocal.get()、threadLocal.initialValue()的返回值。

public class ThreadLocal<T> {
      omitted ......
}

那么ThreadLocal又是如何区分不同线程的呢?

在ThreadLocal类内,还有一个静态内部类ThreadLocalMap

// ThreadLocalMap is a customized hash map suitable only for 
// maintaining thread local values.
static class ThreadLocalMap {
      static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }
      omitted ......
}

 这个内部类,是一个自定义的hashmap,内部Entry的构造函数需要一个ThreadLocal,以及与这个ThreadLocal关联的对象。

但是我们又会发现,ThreadLocalMap类的实例却没有在ThreadLocal中声明,而是在Thread类中

public class Thread implements Runnable {
      /* ThreadLocal values pertaining to this thread. This map is maintained
       * by the ThreadLocal class. */
      ThreadLocal.ThreadLocalMap threadLocals = null;
      omitted ......
}

每个Thread维护一个ThreadLocalMap映射表,这个映射表的key是ThreadLocal实例本身,value是真正需要存储的Object。

 所以知道了,在ThreadLocal中并没有进行copy操作,不像以前理解的拷贝副本那样,下面举一个例子:

public class ThreadLocalTest {
	
	private static People people = new People();
	
	private static ThreadLocal<People> threadLocal = new ThreadLocal<People>(){
		public People initialValue(){
			return people;
		}
	};
	
	public static void main(String[] args) throws InterruptedException {
		new Thread(new Runnable() {
			@Override
			public void run() {
				threadLocal.get().age = 5;
				System.out.println("people = " + threadLocal.get() +  "age = " + threadLocal.get().age);
			}
		}).start();
		
		Thread.sleep(10);
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println("people = " + threadLocal.get() +  "age = " + threadLocal.get().age);
			}
		}).start();
	}

}

class People {
	public int age;
}

 这样一来,在任何一个thread中修改people对象的age,都能够在另外的一个线程中看到

打印结果:

people = thread.People@6f5ab880age = 5

people = thread.People@6f5ab880age = 5

如果将threadLocal中的initialValue()的返回值改为new People,那么才不会相互影响

private static ThreadLocal<People> threadLocal = new ThreadLocal<People>(){
		public People initialValue(){
			return new People();
		}
	};

 打印结果为:

people = thread.People@44bacfa2age = 5

people = thread.People@44bacfa2age = 0

当然,文章还有很多没有讲,比如如何set,不过不想继续贴源码了,到此为止

猜你喜欢

转载自zk-chs.iteye.com/blog/2276851