再了解ThreadLocal之前先看一个简单的Java线程示例。
线程类:
class="java" name="code">public class TestThread2 extends Thread { int a; String b = "a"; @Override public void run() { for (int i = 1; i <= 3; i++) { System.out.println(Thread.currentThread().getName() + " " + a + " " + b); a++; b = "" +(char)(b.charAt(0)+1); } } }
主测试类代码:
public class MainTest { public static void main(String[] args) { Runnable test = new TestThread2(); Thread a1 = new Thread(test,"线程1"); Thread a2 = new Thread(test,"线程2"); Thread a3 = new Thread(test,"线程3"); //a1,a2,a3共享test对象的实例变量 a1.start(); a2.start(); a3.start(); } }
?某个输出结果为:
线程1 10 a 线程1 11 b 线程1 12 c 线程2 13 d 线程3 14 e 线程2 14 e 线程2 15 f 线程3 17 g 线程3 18 h
??????? 由结果可以看到,test对象里的a,b变量被几个线程共享,所以他们的结果累加了。当然如果改变一种写法,几个线程不通过test对象创建,则不构成共享对象,那么几个都只用自己的成员变量,结果就会不一样了。代码:
public class MainTest { public static void main(String[] args) { //Runnable test = new TestThread2(); Thread a1 = new Thread(new TestThread2(),"线程1"); Thread a2 = new Thread(new TestThread2(),"线程2"); Thread a3 = new Thread(new TestThread2(),"线程3"); // Thread a1 = new TestThread2(); // Thread a2 = new TestThread2(); // Thread a3 = new TestThread2(); a1.start(); a2.start(); a3.start(); } }
?运行结果为:
线程1 0 a 线程3 0 a 线程1 1 b 线程1 2 c 线程3 1 b 线程3 2 c 线程2 0 a 线程2 1 b 线程2 2 c
??????? 好了,现在的问题就是能不能让共享的对象里的变量也有上面等效的结果,每个对象都把共享的对象属性处理成自己的局部变量。ThreadLocal就是用来达到这个目的的。更改线程类代码为:
public class TestThread2 extends Thread { private static ThreadLocal<Integer> a = new ThreadLocal<Integer>() { @Override protected Integer initialValue() { return 0; } }; private static ThreadLocal<String> b = new ThreadLocal<String>() { @Override protected String initialValue() { return "a"; } }; @Override public void run() { for (int i = 1; i <= 3; i++) { System.out.println(Thread.currentThread().getName() + " " + a.get() + " " + b.get()); a.set(a.get() + 1); b.set("" + (char) (b.get().charAt(0) + 1)); } } }
?再次运行共享test对象的主程序测试类,打印结果如下:
线程1 0 a 线程2 0 a 线程2 1 b 线程2 2 c 线程3 0 a 线程3 1 b 线程3 2 c 线程1 1 b 线程1 2 c
?对于ThreadLocal的一般解释:
写道 ThreadLocal是什么呢?其实ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是threadLocalVariable(线程局部变量)。也许把它命名为ThreadLocalVar更加合适。线程局部变量(ThreadLocal)其实的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是Java中一种较为特殊的线程绑定机制,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。?ThreadLocal类位于java.lang下,即java.lang.ThreadLocal,对于这个类的解读和实现分析,网上已经有不少了:
http://sishuok.com/forum/blogPost/list/340.html
http://blog.csdn.net/qjyong/article/details/2158097
http://lavasoft.blog.51cto.com/62575/51926/
http://my.oschina.net/lichhao/blog/111362
http://www.iteye.com/topic/103804
?
用自己的话再解释一下:
每个java.lang.Thread线程类里都有一个ThreadLocalMap成员属性(打开源码就能看见):
ThreadLocal.ThreadLocalMap threadLocals = null;
ThreadLocalMap是ThreadLocal的静态内部类。Thread里的这个threadLocals成员属性就是用来存储各个ThreadLocal的key-value映射的。这里的key就是ThreadLocal对象,值就是ThreadLocal里设定的值。拿上面的代码线程类为例:线程a1中的threadLocals存储了两个key-value对,一个是a(ThreadLocal型)-0(int型),另一个是b(ThreadLocal型)-"a"(字符串型)。线程a2,a3同理。