`
zhouchaofei2010
  • 浏览: 1085867 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Thread类中的threadLocals 和ThreadLocal原理

阅读更多

ThreadLocal在1.6版本中不是用一个全局的Map来存各个线程的变量副本,而是在Thread类中有一个ThreadLocalMap的变量,然后用Thread.currentThread().threadLocals.get(this)来引用的各线程变量副本,这样避免了去同步全局的Map

 

ThreadLocal使用的简单例子:

 

 

package com.test;

public class TestNum {
	// ①通过匿名内部类覆盖ThreadLocal的initialValue()方法,指定初始值
	private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>() {
		public Integer initialValue() {
			return 0;
		}
	};

	// ②获取下一个序列值
	public int getNextNum() {
		seqNum.set(seqNum.get() + 1);
		return seqNum.get();
	}

	public static void main(String[] args) {
		TestNum sn = new TestNum();
		// ③ 3个线程共享sn,各自产生序列号
		TestClient t1 = new TestClient(sn);
		TestClient t2 = new TestClient(sn);
		TestClient t3 = new TestClient(sn);
		t1.start();
		t2.start();
		t3.start();
	}

	private static class TestClient extends Thread {
		private TestNum sn;

		public TestClient(TestNum sn) {
			this.sn = sn;
		}

		public void run() {
			for (int i = 0; i < 3; i++) {
				// ④每个线程打出3个序列值
				System.out.println("thread[" + Thread.currentThread().getName() + "] --> sn["
						 + sn.getNextNum() + "]");
			}
		}
	}
}

 

 通常我们通过匿名内部类的方式定义ThreadLocal的子类,提供初始的变量值,如例子中①处所示。TestClient线程产生一组序列号,在③处,我们生成3个TestClient,它们共享同一个TestNum实例。运行以上代码,在控制台上输出以下的结果:

 

thread[Thread-0] --> sn[1]
thread[Thread-1] --> sn[1]
thread[Thread-2] --> sn[1]
thread[Thread-1] --> sn[2]
thread[Thread-0] --> sn[2]
thread[Thread-1] --> sn[3]
thread[Thread-2] --> sn[2]
thread[Thread-0] --> sn[3]
thread[Thread-2] --> sn[3]

 

考察输出的结果信息,我们发现每个线程所产生的序号虽然都共享同一个TestNum实例,但它们并没有发生相互干扰的情况,而是各自产生独立的序列号,这是因为我们通过ThreadLocal为每一个线程提供了单独的副本。

 

 

上面例子中,是在自己的类中定义ThreadLocal,那么,那么,可否直接使用Thread.currentThread().threadLocals?

 

不可以的,因为threadLocals变量在Thread中时package的访问权限,只能在同一个包下访问。

 

但是可以通过反射来得到threadLocals中的内容,参考:

 

http://stackoverflow.com/questions/2001353/java-list-thread-locals

 

 

threadLocals 是干什么用的?

 

是线程存放多个ThreadLocal实例的。

 

 

 

ThreadLocal首先通过当前线程t得到threadLocals,然后把自身this作为key,从threadLocals中得到存储在线程本地的相关的数据

 

ThreadLocal中get 和set方法如下:

 

 

 public void set(T value) {

        Thread t = Thread.currentThread();

        ThreadLocalMap map = getMap(t);

        if (map != null)

            map.set(this, value);

        else

            createMap(t, value);

    }

 

 

 

  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();

    }

    

    

    其中 getMap方法简单如下:

    

  ThreadLocalMap getMap(Thread t) {

        return t.threadLocals;

    }

 

 

 

 

总结ThreadLocal原理:ThreadLocal对象相当于线程私有财产(数据)的经纪人,为线程的私有财产(数据)提供存储和获取的代理功能,而私有财产存在Thread的ThreadLocalMap对象中

 

 

 

 

一个 ThreadLocal对象只对应一个值对象 ,多个ThreadLocal对象和相应的值存在线程中类型为ThreadLocalMap类型的threadLocals变量中

 

 

因为通常把多了属性封装在一个Map,而一个 ThreadLocal对象只对应这个map,但map存有多值,故会给人1个Threadlocal对应多个对象的错误印象

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics