浅谈ThreadLocal----每个线程一个小书包
ThreadLocal是什么?thread是线程,local是本地的意思
字面意思是线程本地。
其实更通俗的理解是给每个线程设置一个缓存。这个缓存用来存储当前线程在未来的业务逻辑中需要执行到的变量。
我们先来看怎么用:
首先创建全局变量ThreadLocal,
各自启动一个线程任务:
线程任务将变量设置到缓存中。
线程任务需要用到缓存中的变量时,直接从缓存中取即可。
1 import java.util.concurrent.TimeUnit;
2
3 /**
4* @discription
5*/
6 public class ThreadLocalLearn {
7 static ThreadLocal<String> threadLocal = new ThreadLocal<>();
8
9 public static void main(String[] args) {
10 Runnable r = new Runnable() {
11 @Override
12 public void run() {
13 threadLocal<strong>.set</strong>(Thread.currentThread().getName());
14 sayMyName();
15 threadLocal.<strong>remove</strong>();
16 }
17
18 public void sayMyName() {
19 for (int i = 0; i < 3; i++) {
20 String name = threadLocal.<strong>get</strong>();
21 System.out.println(Thread.currentThread().getName() + " say: im a thread, name:" + name);
22 try {
23 TimeUnit.SECONDS.sleep(3);
24 } catch (Exception e) {
25 //...
26 }
27 }
28 }
29 };
30 Thread t1 = new Thread(r);
31 t1.start();
32 Thread t2 = new Thread(r);
33 t2.start();
34 }
35 }它的使用非常简单,
(1)先set()存储值;
(2)使用时get()取出值;
(3)用完了使用remove()清理掉;
输出如下:
Connected to the target VM, address: '127.0.0.1:56863', transport: 'socket'
Thread-0 say: im a thread, name:Thread-0
Thread-1 say: im a thread, name:Thread-1
Thread-0 say: im a thread, name:Thread-0
Thread-1 say: im a thread, name:Thread-1
Thread-1 say: im a thread, name:Thread-1
Thread-0 say: im a thread, name:Thread-0
Disconnected from the target VM, address: '127.0.0.1:56863', transport: 'socket'很多人第一次见到ThreadLocal,第一直觉它的实现是用Map 。(防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )但是深入研究之后,你会发现threadLocal的实现要比这样一个map 精妙的多,也好用的多。
我们通过查看java源码,可以依次探索ThreadLocal是如何实现缓存的:
类整体的关系大概是这样的:
查看源码,我们可以发现如下特性:
1、ThreadLocal本身并不是缓存,它只是起到一个缓存的key 的作用。我们每次创建一个ThreadLocal 并不是真正的创建了一个缓存,其实只是创建了一个缓存的标识。
源码如下:this 就是ThreadLocal实例
1 public void set(T value) {
2 Thread t = Thread.currentThread();
3 ThreadLocalMap map = getMap(t);
4 if (map != null) {
5 map.set(this, value);
6 } else {
7 createMap(t, value);
8 }
9 }2、真正的缓存保存在Thread中,缓存被定义为:
ThreadLocal.ThreadLocalMap threadLocals;
从名字可以发现,这个缓存的类型是在ThreadLocal 中定义的一个静态内部类。这个类就是用来真正存放缓存的地方。这就像是thread小书包一样,每个线程有一个自己的独立的存储空间。
设计疑问:它(ThreadLocalMap)为什么没有定义在Thread类中,毕竟它是Thread的缓存。
源码如下:Thread.java
1 /* ThreadLocal values pertaining to this thread. This map is maintained
2 * by the ThreadLocal class. */
3 ThreadLocal.ThreadLocalMap threadLocals = null; 3、查看ThreadLocalMap的源码,我们发现它并没有实现Map接口,就像其他map一样,ThreadLocalMap实现了常用的Map中的set,get,getEntry,setThreshold,,remove 等方法。
并且它内部使用了线性探测法来解决哈希冲突。
设计疑问:它(ThreadLocalMap)为什么没有实现Map接口?
源码如下:ThreadLocal.Java
1 static class ThreadLocalMap {
2
3 //...
4
5 private static final int INITIAL_CAPACITY = 16;
6
7
8 private Entry[] table;
9
10
11 private int size = 0;
12
13
14 private int threshold; // Default to 0
15
16
17 private void setThreshold(int len) {
18 threshold = len * 2 / 3;
19 }
20
21
22 private Entry getEntry(ThreadLocal<?> key) {
23 ...
24 }
25
26
27
28 private void set(ThreadLocal<?> key, Object value) {
29 ...
30 }
31
32
33 private void remove(ThreadLocal<?> key) {
34 ...
35 }
36
37
38 private void rehash() {
39 ...
40 }
41
42 private void resize() {
43 ...
44 }
45 ....
46 }4、继续看源码,我们发现ThreadLocalMap类像其他Map实现一样,在内部定义了Entry。并且这个Entry居然继承了弱引用,弱引用被定义在Entry的key上,而且key的类型是ThreadLocal。
至于什么是弱引用,我以前的文章中介绍过,请看(浅谈Java中的引用 https://www.cnblogs.com/jilodream/p/6181762.html),一定要对弱引用了解,否则ThreadLocal的核心实现以及它会存在的问题,就无法更深理解了。
这里又会有疑问,为什么要使用弱引用,使用强引用不好吗?弱引用万一被回收导致空引用等问题怎么办?
源码如下:ThreadLocal.Java
1 static class Entry extends WeakReference
页:
[1]