[Java] ThreadLocal相关内容
2012-10-18 20:31
453 查看
当谈到线程时,必然要关注多个线程对同一个资源的访问。比如某个线程要读一个变量,为了保证它在读的时候不被其它线程执行写操作,所以要加一个只读锁,这样其它线程就无法再加只写锁或读写锁,但是如果其它线程这时也要读它,可以再加只读锁。多个线程可以同时读这个变量,但是每次只有一个线程可以来写这个变量。这就是线程通过加锁的机制来访问变量。这种情况也就是同一个变量被多个线程共享,所以必须通过加锁进行同步。
看了ThreadLocal的源码,发现和它相关的还有ThreadLocalMap和Thread。对Thread都应该比较熟悉,就是一个线程。ThreadLocalMap从表面上看就是一个ThreadLocal的Map,它里面保存的是多个ThreadLocal->Value(即从ThreadLocal到Value的映射,ThreadLocal用作键,Value是对应的值)。它们之间的关系是,Thread里面定义了一个ThreadLocalMap的变量threadLocals,并且没有进行初始化。当你在一个线程里面第一次访问ThreadLocal时,这个线程的threadLocals变量被初始化为ThreadLocalMap的对象。然后ThreadLocal的对象和对应的值就被存储到变量threadLocals里面。同一个线程可以访问多个ThreadLocal对象,它们和对应的值都存储在同一个变量threadLocals里面。换言之,一个线程有一个ThreadLocalMap类型的变量threadLocals,它里面保存了多个ThreadLocal的对象到对应值的映射。这就是一个线程访问多个ThreadLocal。同样,一个ThreadLocal也可以被多个线程访问,这样每一个线程的ThreadLocalMap类型的变量threadLocals里面都存储了ThreadLocal到对应值的映射。把上面两种情况结合起来,就是多个线程访问多个ThreadLocal。
我们定义了一个ThreadLocal变量,每一个线程在访问它时,都会把这个变量和它对应的值放到线程里面,所以每个线程在读写时都是操作线程内部自己的拷贝。多个线程同时访问ThreadLocal时也不会有问题,我们定义的ThreadLocal变量并没有在线程间共享,而是每个线程自己拷贝了一份。所以不存在加锁和同步问题,当线程完成时,这个本地拷贝会随线程一起释放掉。
下面是一个简单的示例:
运行结果如下:
Thread ID = 7: get = null
Thread ID = 7: set = 10
Thread ID = 7: get = 10
Thread ID = 9: get = null
Thread ID = 9: set = 30
Thread ID = 9: get = 30
Thread ID = 8: get = null
Thread ID = 8: set = 20
Thread ID = 8: get = 20
Thread ID = 10: tl0.get = null
Thread ID = 10: tl1.get = null
Thread ID = 10: tl2.get = null
Thread ID = 10: tl0.set = 10
Thread ID = 10: tl1.set = 20
Thread ID = 10: tl2.set = 30
Thread ID = 10: tl0.get = 10
Thread ID = 10: tl1.get = 20
Thread ID = 10: tl2.get = 30
如果文章有什么不对地方,欢迎指出!
看了ThreadLocal的源码,发现和它相关的还有ThreadLocalMap和Thread。对Thread都应该比较熟悉,就是一个线程。ThreadLocalMap从表面上看就是一个ThreadLocal的Map,它里面保存的是多个ThreadLocal->Value(即从ThreadLocal到Value的映射,ThreadLocal用作键,Value是对应的值)。它们之间的关系是,Thread里面定义了一个ThreadLocalMap的变量threadLocals,并且没有进行初始化。当你在一个线程里面第一次访问ThreadLocal时,这个线程的threadLocals变量被初始化为ThreadLocalMap的对象。然后ThreadLocal的对象和对应的值就被存储到变量threadLocals里面。同一个线程可以访问多个ThreadLocal对象,它们和对应的值都存储在同一个变量threadLocals里面。换言之,一个线程有一个ThreadLocalMap类型的变量threadLocals,它里面保存了多个ThreadLocal的对象到对应值的映射。这就是一个线程访问多个ThreadLocal。同样,一个ThreadLocal也可以被多个线程访问,这样每一个线程的ThreadLocalMap类型的变量threadLocals里面都存储了ThreadLocal到对应值的映射。把上面两种情况结合起来,就是多个线程访问多个ThreadLocal。
我们定义了一个ThreadLocal变量,每一个线程在访问它时,都会把这个变量和它对应的值放到线程里面,所以每个线程在读写时都是操作线程内部自己的拷贝。多个线程同时访问ThreadLocal时也不会有问题,我们定义的ThreadLocal变量并没有在线程间共享,而是每个线程自己拷贝了一份。所以不存在加锁和同步问题,当线程完成时,这个本地拷贝会随线程一起释放掉。
下面是一个简单的示例:
public static void main(String[] args) { final ThreadLocal<Integer> tl = new ThreadLocal<Integer>(); new Thread(new Runnable(){ public void run() { System.out.println("Thread ID = " + Thread.currentThread().getId() + ": get = " + tl.get()); tl.set(10); System.out.println("Thread ID = " + Thread.currentThread().getId() + ": set = " + 10); System.out.println("Thread ID = " + Thread.currentThread().getId() + ": get = " + tl.get()); }}).start(); new Thread(new Runnable(){ public void run() { System.out.println("Thread ID = " + Thread.currentThread().getId() + ": get = " + tl.get()); tl.set(20); System.out.println("Thread ID = " + Thread.currentThread().getId() + ": set = " + 20); System.out.println("Thread ID = " + Thread.currentThread().getId() + ": get = " + tl.get()); }}).start(); new Thread(new Runnable(){ public void run() { System.out.println("Thread ID = " + Thread.currentThread().getId() + ": get = " + tl.get()); tl.set(30); System.out.println("Thread ID = " + Thread.currentThread().getId() + ": set = " + 30); System.out.println("Thread ID = " + Thread.currentThread().getId() + ": get = " + tl.get()); }}).start(); final ThreadLocal<Integer> tl0 = new ThreadLocal<Integer>(); final ThreadLocal<Integer> tl1 = new ThreadLocal<Integer>(); final ThreadLocal<Integer> tl2 = new ThreadLocal<Integer>(); new Thread(new Runnable(){ public void run() { System.out.println("Thread ID = " + Thread.currentThread().getId() + ": tl0.get = " + tl0.get()); System.out.println("Thread ID = " + Thread.currentThread().getId() + ": tl1.get = " + tl1.get()); System.out.println("Thread ID = " + Thread.currentThread().getId() + ": tl2.get = " + tl2.get()); tl0.set(10); tl1.set(20); tl2.set(30); System.out.println("Thread ID = " + Thread.currentThread().getId() + ": tl0.set = " + 10); System.out.println("Thread ID = " + Thread.currentThread().getId() + ": tl1.set = " + 20); System.out.println("Thread ID = " + Thread.currentThread().getId() + ": tl2.set = " + 30); System.out.println("Thread ID = " + Thread.currentThread().getId() + ": tl0.get = " + tl0.get()); System.out.println("Thread ID = " + Thread.currentThread().getId() + ": tl1.get = " + tl1.get()); System.out.println("Thread ID = " + Thread.currentThread().getId() + ": tl2.get = " + tl2.get()); }}).start(); }
运行结果如下:
Thread ID = 7: get = null
Thread ID = 7: set = 10
Thread ID = 7: get = 10
Thread ID = 9: get = null
Thread ID = 9: set = 30
Thread ID = 9: get = 30
Thread ID = 8: get = null
Thread ID = 8: set = 20
Thread ID = 8: get = 20
Thread ID = 10: tl0.get = null
Thread ID = 10: tl1.get = null
Thread ID = 10: tl2.get = null
Thread ID = 10: tl0.set = 10
Thread ID = 10: tl1.set = 20
Thread ID = 10: tl2.set = 30
Thread ID = 10: tl0.get = 10
Thread ID = 10: tl1.get = 20
Thread ID = 10: tl2.get = 30
如果文章有什么不对地方,欢迎指出!
相关文章推荐
- Java中Date及Timestamp时间相关内容
- Java中Date及Timestamp时间相关内容【转】
- Java Calendar,Date,DateFormat,TimeZone,Locale等时间相关内容的认知和使用(1) Calendar
- JAVA解析Excel表格并读取相关内容
- Java 对redis 的操作及相关内容
- Java Calendar,Date,DateFormat,TimeZone,Locale等时间相关内容的认知和使用(1) Calendar
- java序列化相关内容整理
- java中的继承相关内容
- Java Calendar,Date,DateFormat,TimeZone,Locale等时间相关内容的认知和使用(2) 自己封装的Calendar接口
- java -- hashcode相关的内容
- 垃圾回收相关(深入理解Java虚拟机中的内容)
- Java Calendar,Date,DateFormat,TimeZone,Locale等时间相关内容的认知和使用(2) 自己封装的Calendar接口
- eclipse与tomcat及javaweb和mysql相关内容
- java并发相关内容汇总
- javawebday50(ThreadLocal dbutils简易盗版 体会内部内容 queryrunner 增删)
- Java相关技术点及技术内容
- 读取本机的Java运行环境和相关配置文件的内容 推荐
- Java面试题相关内容
- Java Calendar,Date,DateFormat,TimeZone,Locale等时间相关内容的认知和使用(3) Date
- Java多线程复习与巩固(二)--线程相关工具类Timer和ThreadLocal的使用