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
[code]1 static class Entry extends WeakReference |