多线程进阶ThreadLocal
来源:互联网 发布:甘肃政法学院网络教学 编辑:程序博客网 时间:2024/05/20 05:28
线程的私有变量是利用ThreadLocal来实现的,那么怎么来的实现的呢,简单来说,就是Thread包含一变量map,这个map里面的键值对存放的是ThreadLocal —- Value键值对,也就是线程若需要存放多个私有变量,需要new出多个ThreadLocal,如
public class Run { public static void main(String[] args) {// new ThreadImp().start(); new Thread(new Runnable() { public void run() { ThreadLocal<String> t1 = new ThreadLocal<String>(); t1.set("123");//到这里时线程A里面的map存放了t1--"123"键值对 ThreadLocal<String> t2 = new ThreadLocal<String>(); t2.set("345");//到这里时线程A里面的map存放了t1--"123",t2--"345"两个键值对 System.out.println(t1.get()); System.out.println(t2.get()); } },"线程A").start(); ThreadLocal<Date> t = new ThreadLocal<Date>(); //这里如果不set值的话,下面的get就会返回一个null,另外可以自己实现一 //个ThreadLocal重新定义这个初始值 t.set(new Date()); while(Thread.activeCount()>1){ } System.out.println(t.get()); }}
输出
123
345
Fri Oct 20 15:42:41 CST 2017
先来分析下源码
分析源码前先看下类的成员的访问权限情况
主要的类有三个,Thread,ThreadLocal,ThreadLocalMap,
ThreadLocalMap是ThreadLocal的一个内部静态类,Thread中含有一个ThreadLocalMap的引用,ThreadLocalMap就相当于一个Map,其存放的键值对就是ThreadLocal—value.
publicclass Thread implements Runnable {/* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ //Thread里面含有一个map<ThreadLocal,Object>,注意其为default的访问权限,同包下可以访问 ThreadLocal.ThreadLocalMap threadLocals = null;}package java.lang;import java.lang.ref.*;import java.util.concurrent.atomic.AtomicInteger;public class ThreadLocal<T> { /** * threadlocal的哈希值,下面的ThreadlocalMap中有个table数组,里面存放的就是ThreadLocal, * 而其在table数组中的索引就是根据这个算出来的 */ private final int threadLocalHashCode = nextHashCode(); //注意这个是静态变量,类初始化的时候就已经显示初始化值了 private static AtomicInteger nextHashCode = new AtomicInteger(); /** * The difference between successively generated hash codes - turns * implicit sequential thread-local IDs into near-optimally spread * multiplicative hash values for power-of-two-sized tables. */ private static final int HASH_INCREMENT = 0x61c88647; /** * 每new出一个ThreadLocal时都会产生一个唯一不同的hashcode值 */ private static int nextHashCode() { return nextHashCode.getAndAdd(HASH_INCREMENT); } //线程的私有变量初始值为null protected T initialValue() { return null; } /** * Creates a thread local variable. */ public ThreadLocal() { } /** * Returns the value in the current thread's copy of this * thread-local variable. If the variable has no value for the * current thread, it is first initialized to the value returned * by an invocation of the {@link #initialValue} method. * * @return the current thread's value of this thread-local * 获取当前线程map中当前ThrteadLocal对应的私有属性 */ 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(); } /** * Variant of set() to establish initialValue. Used instead * of set() in case user has overridden the set() method. *设置当前线程map中当前ThrteadLocal对应的私有属性的初始值 * @return the initial value */ private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); return value; } /** * Sets the current thread's copy of this thread-local variable * to the specified value. Most subclasses will have no need to * override this method, relying solely on the {@link #initialValue} * method to set the values of thread-locals. *设置当前线程map中当前ThreadLocal对应的私有属性 * @param value the value to be stored in the current thread's copy of * this thread-local. */ public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); } /** * Removes the current thread's value for this thread-local * variable. If this thread-local variable is subsequently * {@linkplain #get read} by the current thread, its value will be * reinitialized by invoking its {@link #initialValue} method, * unless its value is {@linkplain #set set} by the current thread * in the interim. This may result in multiple invocations of the * <tt>initialValue</tt> method in the current thread. * * @since 1.5 */ public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this); } /** * Get the map associated with a ThreadLocal. Overridden in * InheritableThreadLocal. *获取线程中的map * @param t the current thread * @return the map */ ThreadLocalMap getMap(Thread t) { return t.threadLocals; } /** * Create the map associated with a ThreadLocal. Overridden in * InheritableThreadLocal. *为t线程的map初始化,并存入一个私有属性值 * @param t the current thread * @param firstValue value for the initial entry of the map * @param map the map to store. */ void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); } /** * Factory method to create map of inherited thread locals. * Designed to be called only from Thread constructor. * * @param parentMap the map associated with parent thread * @return a map containing the parent's inheritable bindings */ static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) { return new ThreadLocalMap(parentMap); } /** * Method childValue is visibly defined in subclass * InheritableThreadLocal, but is internally defined here for the * sake of providing createInheritedMap factory method without * needing to subclass the map class in InheritableThreadLocal. * This technique is preferable to the alternative of embedding * instanceof tests in methods. */ T childValue(T parentValue) { throw new UnsupportedOperationException(); } /** *ThreadLocal的一个内部静态类,和HashMap的实现有点类似 */ static class ThreadLocalMap { /** * The entries in this hash map extend WeakReference, using * its main ref field as the key (which is always a * ThreadLocal object). Note that null keys (i.e. entry.get() * == null) mean that the key is no longer referenced, so the * entry can be expunged from table. Such entries are referred to * as "stale entries" in the code that follows. */ static class Entry extends WeakReference<ThreadLocal> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal k, Object v) { super(k); value = v; } } /** * The initial capacity -- MUST be a power of two. */ private static final int INITIAL_CAPACITY = 16; /** *实体内容数组 * The table, resized as necessary. * table.length MUST always be a power of two. */ private Entry[] table; /** * The number of entries in the table. */ private int size = 0; /** * The next size value at which to resize. */ private int threshold; // Default to 0 /** * Set the resize threshold to maintain at worst a 2/3 load factor. */ private void setThreshold(int len) { threshold = len * 2 / 3; } /** * Increment i modulo len. */ private static int nextIndex(int i, int len) { return ((i + 1 < len) ? i + 1 : 0); } /** * Decrement i modulo len. */ private static int prevIndex(int i, int len) { return ((i - 1 >= 0) ? i - 1 : len - 1); } /** * Construct a new map initially containing (firstKey, firstValue). * ThreadLocalMaps are constructed lazily, so we only create * one when we have at least one entry to put in it. */ ThreadLocalMap(ThreadLocal firstKey, Object firstValue) { table = new Entry[INITIAL_CAPACITY]; int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1); //计算ThreadLocal--value对应的实体在table中的索引位置 table[i] = new Entry(firstKey, firstValue); size = 1; setThreshold(INITIAL_CAPACITY); } /** * Construct a new map including all Inheritable ThreadLocals * from given parent map. Called only by createInheritedMap. * * @param parentMap the map associated with parent thread. */ private ThreadLocalMap(ThreadLocalMap parentMap) { Entry[] parentTable = parentMap.table; int len = parentTable.length; setThreshold(len); table = new Entry[len]; for (int j = 0; j < len; j++) { Entry e = parentTable[j]; if (e != null) { ThreadLocal key = e.get(); if (key != null) { Object value = key.childValue(e.value); Entry c = new Entry(key, value); int h = key.threadLocalHashCode & (len - 1); while (table[h] != null) h = nextIndex(h, len); table[h] = c; size++; } } } } /** * Get the entry associated with key. This method * itself handles only the fast path: a direct hit of existing * key. It otherwise relays to getEntryAfterMiss. This is * designed to maximize performance for direct hits, in part * by making this method readily inlinable. * * @param key the thread local object * @return the entry associated with key, or null if no such */ private Entry getEntry(ThreadLocal key) { int i = key.threadLocalHashCode & (table.length - 1); Entry e = table[i]; //如果能在table中找到key则返回,否则查找下一个位置 if (e != null && e.get() == key) return e; else return getEntryAfterMiss(key, i, e); } /** * Set the value associated with key. *将ThreadLocal--value键值对存入线程的map中 * @param key the thread local object * @param value the value to be set */ private void set(ThreadLocal key, Object value) { // We don't use a fast path as with get() because it is at // least as common to use set() to create new entries as // it is to replace existing ones, in which case, a fast // path would fail more often than not. Entry[] tab = table; int len = tab.length; int i = key.threadLocalHashCode & (len-1); for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) { ThreadLocal k = e.get(); if (k == key) { e.value = value; return; } if (k == null) { replaceStaleEntry(key, value, i); return; } } tab[i] = new Entry(key, value); int sz = ++size; if (!cleanSomeSlots(i, sz) && sz >= threshold) rehash(); } } }}
对照着这个,自己实现了一个简洁的ThreadLocal,方便理解
public class MyThread extends Thread{ MyThreadLocal.MyThreadLocalMap mythreadlocals;}
public class MyThreadLocal<T> { protected T initialValue() { return (T) "初始值"; } public void set(T value){ MyThread t = (MyThread) MyThread.currentThread(); MyThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); } public T get() { MyThread t = (MyThread) MyThread.currentThread(); MyThreadLocalMap map = getMap(t); if (map != null) { MyThreadLocalMap.Entry e = map.getEntry(this); if (e != null) return (T)e.value; } return setInitialValue(); } private void createMap(MyThread t,T value){ t.mythreadlocals = new MyThreadLocalMap(this, value); } MyThreadLocalMap getMap(MyThread t) { return t.mythreadlocals; } private T setInitialValue() { T value = initialValue(); MyThread t = (MyThread) MyThread.currentThread(); MyThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); return value; } static class MyThreadLocalMap{ static class Entry{ MyThreadLocal key; Object value; Entry(MyThreadLocal key,Object value){ this.key = key; this.value = value; } MyThreadLocal get(){ return key; } } private static final int INITIAL_CAPACITY = 16; Entry[] table; MyThreadLocalMap(MyThreadLocal firstKey, Object firstValue) { table = new Entry[INITIAL_CAPACITY]; table[0] = new Entry(firstKey, firstValue); } private static int prevIndex(int i, int len) { return ((i - 1 >= 0) ? i - 1 : len - 1); } private static int nextIndex(int i, int len) { return ((i + 1 < len) ? i + 1 : 0); } private Entry getEntry(MyThreadLocal key) { Entry e = table[0]; for(int i=0;i<table.length;i++){ if(table[i]!=null){ if(table[i].key == key){ return table[i]; } } } return null; } private void set(MyThreadLocal key, Object value) { Entry[] tab = table; int len = tab.length; int i = 0; for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) { MyThreadLocal k = e.get(); if (k == key) { e.value = value; return; } if (k == null) { tab[i].key = key; tab[i].value = value; return; } } tab[i] = new Entry(key, value); } }}public class ThreadImp extends MyThread{ @Override public void run() { MyThreadLocal<String> local1 = new MyThreadLocal<String>(); local1.set("新值"+getName()); System.out.println(local1.get()); MyThreadLocal<String> local2 = new MyThreadLocal<String>(); System.out.println(local2.get()); }}package com.lzzl.thread9;public class Run1 { public static void main(String[] args) { new ThreadImp().start(); }}
输出
新值Thread-0
初始值
阅读全文
0 0
- 多线程进阶ThreadLocal
- 多线程 - ThreadLocal
- 多线程---threadLocal
- java高级进阶关于java多线程的应用 ThreadLocal多线程实例详解
- java高级进阶关于java多线程的应用 ThreadLocal多线程实例详解
- Java多线程之ThreadLocal
- Java多线程之ThreadLocal
- ThreadLocal与多线程
- JAVA多线程之ThreadLocal
- JAVA多线程----ThreadLocal
- Java多线程之 ThreadLocal
- 多线程编程1-----ThreadLocal
- Java多线程中的ThreadLocal
- 多线程之threadLocal
- java多线程<一>ThreadLocal
- 多线程之ThreadLocal类
- java多线程之ThreadLocal
- Java多线程之----ThreadLocal
- Java Web 程序员如何转型大数据
- 宏的使用
- java生成验证码
- SSH框架整合 基于 XML 的配置
- Java对象的创建
- 多线程进阶ThreadLocal
- c语言运算过程中的类型自动转换原则
- BZOJ4721(NOIP2016)[蚯蚓]--队列
- [AHK]用AutoHotkey当批处理,批量修改文件名
- 记录关于JavaScript 浮点数运算的精度问题
- QTcpSocket客户端和服务端发送图片(或大文件)小Demo
- 1033. 旧键盘打字(20)
- 求递归算法时间复杂度:递归树
- Nginx详细安装部署教程(二)