标签:clean slots [] 获取值 类的构造函数 yaf ide number 强制
一个实体类,里面有一个Threadlocal类
只能通过get和set方法去访问该对象的值
public class MyNumber {
private static ThreadLocal<Integer> number = new ThreadLocal<Integer>() {
protected Integer initialValue() {
return 0;
}
};
public Integer getNext() {
number.set(number.get() + 1);
return number.get();
}
public static void main(String[] args) throws InterruptedException {
MyNumber myNumber = new MyNumber();
ExecutorService es = Executors.newCachedThreadPool();
for (int i = 0; i < 2; i++) {
es.execute(new MyThread(myNumber));
}
TimeUnit.SECONDS.sleep(3);
es.shutdownNow();
}
}
线程类:MyThread,其里面有一个属性,MyNumber,在run方法里,对LocalThread里保存的值其进行加1操作
public class MyThread implements Runnable {
private MyNumber myNumber;
public MyThread(MyNumber myNumber) {
this.myNumber = myNumber;
}
@Override
public void run() {
for(int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()
+ "-number: " + myNumber.getNext());
}
}
}
输出结果:
pool-1-thread-2-number: 1
pool-1-thread-1-number: 1
pool-1-thread-2-number: 2
pool-1-thread-2-number: 3
pool-1-thread-2-number: 4
pool-1-thread-2-number: 5
pool-1-thread-1-number: 2
pool-1-thread-1-number: 3
pool-1-thread-1-number: 4
pool-1-thread-1-number: 5
创建了两个线程,都将调用mynumber的getNext()方法,但两个线程的操作互不影响。
从输出结果可以看出:确实为每个线程通过ThreadLocal为每个线程创建了一个Integer的存储区域,通过set和get去设置和获得这个值。
源码中,ThreadLocal是泛型类的,每个线程都将会为这个T类型的值创建存储区域
构造函数:是一个默认构造函数
public ThreadLocal() {}
在MyNumber类中,初始化ThreadLocal时重写了initialValue()方法,因为该方法默认返回null
protected T initialValue() {
return null;
}
对于基本类型包装类我们肯定不想返回值是null,所以进行了重写
get方法
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
在获取值的时候,首先要获得当前的线程,以便确定是针对哪个线程获取其中的ThreadLocal保存的值。通过getMap方法获取键值对,获得其中的value值,如果值不等于null,则进行强制转化以后返回,为空,则对其进行初始化一次,setInitialValue()的代码如下
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;
}
其初始化的值仍为initialValue()方法返回的值,这里如果map为空,则会创建一个集合。
getMap方法:
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
Thread类中:
ThreadLocal.ThreadLocalMap threadLocals = null;
说明每一个线程类中都有threadLocals,getMap方法获得当前线程的的threadsLocals的值,是一个ThreadLocalMap类
重点讲解一下ThreadLocal中的Map操作。
讲Map的时候先讲一下ThreadLocalMap的静态内部类Entry,继承了WeakReference,在无法使用它时,垃圾收集器会将其回收。里面有一个value的属性,用于保存线程的值。
static class Entry extends WeakReference<ThreadLocal<?>> {
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
}
它的super是WeakReference,最终将调用Reference这个类的构造函数。这个类主要是用来为Entry设置一个value值,并调用Refernce构造函数。
获得Entry的方法也是通过i
private Entry getEntry(ThreadLocal<?> key) {
int i = key.threadLocalHashCode & (table.length - 1);
Entry e = table[i];
if (e != null && e.get() == key)
return e;
else
return getEntryAfterMiss(key, i, e);
}
}
ThreadLocalMap是ThreadLocal的静态内部类
其中一个构造函数:
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
}
首先确定了Entry[]数组的大小,通过与运算获得value存储在数组中的第几p的实现方式有点类似
get方法中首先通过getMap方法获得对应的ThreadLocalMap,并通过getEntry()方法获得Entry对象,从而获得value的值
set方法
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
set方法里的核心方法应该是ThreadMap类中的set方法
private void set(ThreadLocal<?> key, Object value) {
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();
}
该段的意思是首先通过计算hash并做与运算,计算出存储位置,通过存储位置获得value,如果value不为空,则重置value的值,否则table[i]的位置则为Entry
因为getMap获取的是当前线程的threadLocals,其初始时值为0,所以set时,先调用 createMap(t, value)方法:
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this,firstValue);
}
为当前线程的threadLocals进行初始化,传入了一个threadLocal对象和初始化值。
标签:clean slots [] 获取值 类的构造函数 yaf ide number 强制
原文地址:http://www.cnblogs.com/Hdaydayup/p/7593970.html