ThreadLocal的思考:
描述:
方法1:传入秒数,new一个SimpleDataFormat对象,返回时间字符串
方法2:生成两个线程,每个线程都去调用方法1来打印不同秒数的时间
结果:运行正常
进一步思考:要是1000个线程呢?用线程池,生成10线程
进一步思考:在方法1中,每次调用都会new一个SimpleDataFormat对象,浪费开销
解决方法:将SimpleDataFormat作为全局变量
运行结果:线程出现并发冲突问题,会有相同时间结果。原因是多个线程共享了SimpleDataFormat对象。
解决方法:加锁,用synchronized
进一步思考:虽然现在sm只生成了一次,但多个线程在加锁部分部分代码是串行执行的,没有并发,效率低
优化:在线程池有10线程,让每个线程都有自个的sm对象,这样,10线程之间就可以并发执行,sm也没有创建很多个
实现方式: 用ThreadLocal给当前线程赋予独立的变量
另一个场景,服务器接收请求,有用户信息,不同方法使用同一个用户信息。
分析:不同请求对应不同线程,每个线程都用ThreadLocal来保存用户信息,则不会发生冲突,且用户信息也不用作为方法参数传来传去
源码分析: 在Thread对象中,有一个map,key为ThreadLocal对象,value为用户定义的值,这样,每个线程都有独立的变量存储map,且可以保存多个不同的值。
Spring中的应用:RequestContextHolder中用ThreadLocal来保存请求的各种信息RequestAttributes
示例代码:
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 多个线程打印时间练习:多个独立线程打印,打印出不同秒数后的时间
* 使用了ThreadLocal,线程池中每个线程都有自个的SimpleDateFormat对象,不用重复创建
*/
public class test03 {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
ThreadLocal<SimpleDateFormat> simpleDateFormatThreadLocal
= new ThreadLocal<SimpleDateFormat>(){
@Override
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
}
};
//可以有多个ThreadLocal来保存多个变量值,用 lambda 表达式简化初始化
ThreadLocal<String> stringThreadLocal = ThreadLocal.withInitial(()->"test");
for(int i=0;i<1000;i++){
final int temp = i;
executorService.execute(new Runnable() {
@Override
public void run() {
Date date = new Date(temp*1000);
String dateStr = simpleDateFormatThreadLocal.get().format(date);
System.out.println(dateStr); //输出结果不会有重复
System.out.println(stringThreadLocal.get());
}
});
}
}
}
来源:CSDN
作者:简单点,编程的方式简单点
链接:https://blog.csdn.net/bin1165323/article/details/104612608