(Java多线程系列八)ThreadLocal
ThreadLocal
1、什么是ThreadLocal
ThreadLocal是保存线程本地化对象的容器,当运行于多线程环境的某个对象用ThreadLocal维护变量时,ThreadLocal为每个使用变量的线程分配一个独立的变量副本。所以每个线程都可以独立的改变自己的副本,而不会影响其他线程所对应的副本。
从线程的角度看,这个变量就像线程专有的本地变量,这也是类名中"Local"所要表达的意思。
2、一个ThreadLocal的示例
class Entity {
// 使用重写initialValue方法初始化值
// public ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>() {
// @Override
// protected Integer initialValue() {
// return 0;
// }
// };
// 使用lambda表达式初始化值
public ThreadLocal<Integer> seqNum = ThreadLocal.withInitial(() -> 0);
public int getNextSeqNum() {
seqNum.set(seqNum.get() + 1);
return seqNum.get();
}
}
class ThreadDemo extends Thread {
private Entity entity;
public ThreadDemo(Entity entity) {
this.entity = entity;
}
@Override
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println(getName() + "=====" + entity.getNextSeqNum());
}
}
}
public class ThreadLocalDemo {
public static void main(String[] args) {
Entity entity = new Entity();
ThreadDemo threadDemo01 = new ThreadDemo(entity);
ThreadDemo threadDemo02 = new ThreadDemo(entity);
threadDemo01.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
threadDemo02.start();
}
}
3、实现个简单的ThreadLocal
public class SimpleThreadLocal<T> {
private Map<Thread, T> map = Collections.synchronizedMap(new HashMap<>());
public void set(T val) {
map.put(Thread.currentThread(), val);
}
public T get() {
Thread thread = Thread.currentThread();
if (map.containsKey(thread)) {
return map.get(thread);
} else {
T t = init();
map.put(thread, t);
return t;
}
}
public void remove() {
map.remove(Thread.currentThread());
}
public T init() {
return null;
}
}
下面我们调用自己实现的ThreadLocal测试效果
class Entity01 {
public SimpleThreadLocal<Integer> seqNum = new SimpleThreadLocal<Integer>() {
@Override
public Integer init() {
return 0;
}
};
public int getNextSeqNum() {
seqNum.set(seqNum.get() + 1);
return seqNum.get();
}
}
class ThreadDemo01 extends Thread {
private Entity01 entity;
public ThreadDemo01(Entity01 entity) {
this.entity = entity;
}
@Override
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println(getName() + "=====" + entity.getNextSeqNum());
}
}
}
public class SimpleThreadLocalDemo {
public static void main(String[] args) {
Entity01 entity = new Entity01();
ThreadDemo01 threadDemo01 = new ThreadDemo01(entity);
ThreadDemo01 threadDemo02 = new ThreadDemo01(entity);
threadDemo01.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
threadDemo02.start();
}
}
可以看到实现了同样的效果
4、ThreadLocal与Thread同步机制的比较
对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式:访问串行化,对象共享化
ThreadLocal采用了“以空间换时间”的方式:访问并行化,对象共享化
前者仅提供了一份变量,让不同的线程排队访问;而后者为每个线程都提供了一份变量,因此可以同时访问而互不影响。