定义
提供线程局部变量;一个线程线程局部变量在多个线程中,分别有独立的值(副本)。
特点
简单(开箱即用)、快速(无额外开销)、安全(线程安全)。
场景
多线程场景(资源持有、线程一致性、并发计算、线程安全等场景)。
实现原理
Java中用哈希表实现。
应用范围
几乎所有提供多线程特征的语言。
public class ThreadLocalTest {
public static ThreadLocal<Long> x = new ThreadLocal<Long>(){
@Override
protected Long initialValue() {
System.out.println(Thread.currentThread().getId() + " Initial value run...");
return Thread.currentThread().getId();
}
};
public static void main(String[] args) {
new Thread(()->{
System.out.println(x.get());
}).start();
x.set(100L);
//x.remove();
System.out.println(x.get());
}
}
线程资源持有
持有线程资源供线程的各个部分使用,全局获取,减少编程难度。
线程资源一致性
帮助需要保持线程一致的资源(如数据库事务)维护一致性,降低编程难度。
线程安全
帮助只考虑了单线程的程序库,无缝向多线程场景迁移。
分布式计算
帮助分布式计算场景的各个线程累积局部计算结果。
Apache ab 压力并发测试工具的使用
用synchronize实现线程安全的缺点
性能得不到满足。
用ThreadLocal实现并发线程安全
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class StatController {
//static Integer c =0;
static ThreadLocal<Integer> c = new ThreadLocal<Integer>(){
@Override
protected Integer initialValue(){
return 0;
}
};
void _add(){
try {
Thread.sleep(100);
c.set(c.get() + 1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@RequestMapping("/stat")
public Integer stat(){
return c.get();
}
@RequestMapping("/add")
public Integer add(){
_add();
return 1;
}
}
上面的代码是有问题的,因为获取的值是每个线程自己的变量值,每次累加的也是每个线程自己的累加值。
正确的写法应该是:
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashSet;
@RestController
public class StatController {
static HashSet<Val<Integer>> set = new HashSet<Val<Integer>>();
synchronized static void addSet(Val<Integer> v){
set.add(v);
}
static ThreadLocal<Val<Integer>> c = new ThreadLocal<Val<Integer>>(){
@Override
protected Val<Integer> initialValue(){
Val<Integer> v = new Val<>();
v.setV(0);
addSet(v);
return v;
}
};
void _add(){
try {
Thread.sleep(100);
Val<Integer> v = c.get();
v.setV(v.getV() + 1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@RequestMapping("/stat")
public Integer stat(){
return set.stream().map(x-> x.getV()).reduce((a,x)-> a+x).get();
}
@RequestMapping("/add")
public Integer add(){
_add();
return 1;
}
}
public class Val<T> {
T v;
public T getV() {
return v;
}
public void setV(T v) {
this.v = v;
}
}