2017-11-18 | ThreadLocal | UNLOCK

对ThreadLocal的思考

对ThreadLocal的思考

ThreadLocal 直译过来是 ‘本地线程’,这个理解是不正确的。来看一个案例。

1.0 案例

先是一个接口

1
2
3
public interface Sequence {
int getNumber();
}

实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
public class SequenceA implements Sequence{
static int i = 0;
public int getNumber() {
return i++;
}

public static void main(String[] args){
SequenceA sequenceA = new SequenceA();
new MyThread(sequenceA).start();
new MyThread(sequenceA).start();
new MyThread(sequenceA).start();
}
}

//线程类

1
2
3
4
5
6
7
8
9
10
11
12
13
public class MyThread extends Thread {
private Sequence sequence;

public MyThread(Sequence sequence){
this.sequence = sequence;
}

public void run() {
for(int i=0;i<4;i++){
System.out.println(Thread.currentThread().getName()+"--"+sequence.getNumber());
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
运行结果
Thread-0--0
Thread-0--1
Thread-0--2
Thread-0--3
Thread-1--4
Thread-1--5
Thread-1--6
Thread-1--7
Thread-2--8
Thread-2--9
Thread-2--10
Thread-2--11

Process finished with exit code 0

因为

1
static int i = 0;

是静态的 是所有线程所共享的,所以会出现以上结果,那么我希望每个线程都有独立的 i 呢?

这时候ThreadLocal 派上用场了,

稍微改造了一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class SequenceA implements Sequence{

private static ThreadLocal<Integer> contaner = new ThreadLocal<Integer>(){
@Override
protected Integer initialValue() {
return 0;
}
};

public int getNumber(){
contaner.set(contaner.get()+1);
return contaner.get();
}


public static void main(String[] args){
SequenceA sequenceA = new SequenceA();
new MyThread(sequenceA).start();
new MyThread(sequenceA).start();
new MyThread(sequenceA).start();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
输出结果:

Thread-0--1
Thread-0--2
Thread-0--3
Thread-0--4
Thread-1--1
Thread-1--2
Thread-1--3
Thread-1--4
Thread-2--1
Thread-2--2
Thread-2--3
Thread-2--4



这才是我要的结果嘛,可是为什么 明明是 static的变量 却 每个线程都有了一份,,其实ThreadLocal其实相当于一个容器,它为每个线程 保存了 一个副本

那么 我们有必要来了解下ThreadLocal是怎么实现的 还有为什么我们要实现

它的 initialValue 方法
1
2
3
protected T initialValue() {
return null;
}

这是它的源码 方式是protected 那么 它就是提示我们去 现实它,

以下是它的源码 可以看出来 它里面封装了 一个Map 容器 来实现

1
2
3
4
5
6
7
8
9
10
11
12
13
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();
}

有兴趣可以看看它的源码

评论加载中