直接聊技术!
描述
ThreadLocal直译为 本地线程,但是实际意思却不是这样的,它是一个容器,用于存放本地线程的局部变量,到底为什么叫ThreadLocal,讲道理,我也不知道!
业务描述 在一个类中调用三个线程,三个线程分别进行报数1、2、3
/**
* [@author](https://my.oschina.net/arthor):稀饭
* [@time](https://my.oschina.net/u/126678):下午8:10:59
* @filename:Sequence.java
*/
package demo;
public interface Sequence {
public int getNumber();
}
/**
* [@author](https://my.oschina.net/arthor):稀饭
* [@time](https://my.oschina.net/u/126678):下午8:12:24
* @filename:ClientThread.java
*/
package demo;
public class ClientThread extends Thread {
private Sequence sequence;
public ClientThread(Sequence sequence) {
// TODO Auto-generated constructor stub
this.sequence = sequence;
}
/**
* @Title: run
* @Description: TODO
*/
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName() + " ==> " + sequence.getNumber());
}
}
}
/**
* @author:稀饭
* @time:下午8:18:27
* @filename:TestA.java
*/
package demo;
public class TestA implements Sequence {
private static int number = 0;
@Override
public int getNumber() {
// TODO Auto-generated method stub
number = number + 1;
return number;
}
public static void main(String[] args) {
Sequence sequence = new TestA();
ClientThread clientThread1 = new ClientThread(sequence);
ClientThread clientThread2 = new ClientThread(sequence);
ClientThread clientThread3 = new ClientThread(sequence);
clientThread1.start();
clientThread2.start();
clientThread3.start();
}
}
运行结果如下: Thread-0 ==> 1 Thread-2 ==> 3 Thread-1 ==> 2 Thread-2 ==> 5 Thread-0 ==> 4 Thread-2 ==> 7 Thread-1 ==> 6 Thread-0 ==> 8 Thread-1 ==> 9
**源码分析:**Thread没有按照先后顺序输出,这个可以理解,毕竟线程的启动是随机的,而为什么输出的结果不是1、2、3、1、2、3、1、2、3呢,仔细分析才发现,number是static的,是类所共享的,无法保证对不同线程来说是安全的,大家操作的都是同一个变量,当然一直在递增了。
那么如何做到各自线程递增这样的结果呢?
现在引入ThreadLocal,源码如下 /** * @author:稀饭 * @time:下午8:18:27 * @filename:TestA.java */ package demo;
public class TestB implements Sequence {
private static ThreadLocal<Integer> container = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
// TODO Auto-generated method stub
return 0;
}
};
@Override
public int getNumber() {
// TODO Auto-generated method stub
container.set(container.get() + 1);
return container.get();
}
public static void main(String[] args) {
Sequence sequence = new TestB();
ClientThread clientThread1 = new ClientThread(sequence);
ClientThread clientThread2 = new ClientThread(sequence);
ClientThread clientThread3 = new ClientThread(sequence);
clientThread1.start();
clientThread2.start();
clientThread3.start();
}
}
运行结果如下: Thread-0 ==> 1 Thread-1 ==> 1 Thread-2 ==> 1 Thread-1 ==> 2 Thread-0 ==> 2 Thread-1 ==> 3 Thread-2 ==> 2 Thread-0 ==> 3 Thread-2 ==> 3
源码解析:在TestA中引入ThreadLocal之后输出的结果变成了我上面说的那样,用了ThreadLocal之后每个线程独立了,虽然同样是static,但是线程独立了,也就是说ThreadLocal会为每一个不同的线程设置一个独立的副本。
现在才是最重要的地方,我们自己来实现一个ThreadLocal
先来分析一下ThreadLocal的api:
public void set(T vlue) 将值放入线程局部变量中
public T get() 从线程局部变量中获取
public void remove() 从线程局部中移除值
protected T initialValue() 返回线程局部变量中的初始值
以下是我自己实现的ThreadLocal
/**
* @author:稀饭
* @time:上午10:36:34
* @filename:ThreadLocalContainer.java
*/
package demo;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class ThreadLocalContainer<T> {
private T value;
//这里使用了同步Map
private Map<String, T> map = Collections.synchronizedMap(new HashMap<String, T>());
// 将值放入线程局部变量中
public void set(T vlue) {
map.put(Thread.currentThread().getName(), vlue);
}
// 从线程局部变量中获取
public T get() {
if (!map.containsKey(Thread.currentThread().getName())&&map.get(Thread.currentThread().getName()) == null) {
value = initialValue();
map.put(Thread.currentThread().getName(), value);
}
T v = map.get(Thread.currentThread().getName());
return v;
}
// 从线程局部中移除值
public void remove() {
if (map.containsKey(Thread.currentThread().getName())) {
map.remove(Thread.currentThread().getName());
}
}
// 返回线程局部变量中的初始值
protected T initialValue() {
return value;
}
}
**源码分析:**在源码中我使用了线程安全的Map也就是同步Map,目的是为了防止出现多线程出现的不安全问题。
**Note:发布的这些文章全都是自己边学边总结的,难免有纰漏,如果发现有不足的地方,希望可以指出来,一起学习咯,么么哒。 开源爱好者,相信开源的力量必将改变世界: ** osc : https://git.oschina.net/xi_fan github: https://github.com/wiatingpub