线程的私有变量是利用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.
public
class 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
初始值