ThreadLocal
ThreadLocal 3种使用方式
方法1:
public class ThreadLocalDemo1 {
// 创建线程的私有变量
private static ThreadLocal<String> threadLocal =
new ThreadLocal<>();
public static void main1(String[] args) {
//定义公共任务
Runnable runnable = new Runnable() {
@Override
public void run() {
String tname=Thread.currentThread().getName();
System.out.println(tname+" 设置值:"+tname);
//set ThreadLocal
try {
threadLocal.set(tname);
printThreadLocal();
}finally {
//移除 ThreadLocal
threadLocal.remove();
}
}
};
Thread t1=new Thread(runnable,"线程1");
t1.start();
Thread t2=new Thread(runnable,"线程2");
t2.start();
}
private static void printThreadLocal() {
String re = threadLocal.get();
System.out.println(Thread.currentThread().getName()+" 中取值:"+re);
}
}
方法2:
private static ThreadLocal<Integer> threadLocal =
new ThreadLocal(){
@Override
protected Object initialValue() {
int num=new Random().nextInt(10);
System.out.println("执行了initialValue 生成随机值"+num);
return num;
}
};
public static void main(String[] args) {
//创建线程池
ThreadPoolExecutor executor =
new ThreadPoolExecutor(1,1,0, TimeUnit.SECONDS
,new LinkedBlockingQueue<>(1000));
executor.submit(new Runnable() {
@Override
public void run() {
//get threadlocal
int re = threadLocal.get();
System.out.println(Thread.currentThread().getName()+"得到的结果1:"+re);
}
});
executor.submit(new Runnable() {
@Override
public void run() {
//get threadlocal
int re = threadLocal.get();
System.out.println(Thread.currentThread().getName()+"得到的结果2:"+re);
}
});
}
}
方法3:
public class ThreadLocalDemo4 {
//创建并初始化ThreadLocal
private static ThreadLocal<String> threadLocal =
ThreadLocal.withInitial(new Supplier<String>() {
@Override
public String get() {
System.out.println("执行了withInitial");
return Thread.currentThread().getName();
}
});
public static void main(String[] args) {
Runnable runnable = new Runnable() {
@Override
public void run() {
String re = threadLocal.get();
System.out.println(Thread.currentThread().getName()+":" + re);
}
};
Thread t1 = new Thread(runnable);
t1.start();
Thread t2 = new Thread(runnable);
t2.start();
}
}
举个例子:
ThreadLocal(线程的私有变量)|(本地土著将房子组给剧组)
Thread(剧组)-> ThreadLocalMap(存储的使用线程的值)(租的房子)-> Entry[](剧本) -> key( 扮演者 threadLocal),value(角色)
面试题:ThreadLocal 的 init 在什么情况下不执行
ThreadLocal在执行 get() 的时候才去判断并调用初始化方法
ThreadLocal 经典使用场景:
- 解决线程不安全的问题
- 线程级的数据传递(可以实现一定程度的解耦)
ThreadLocal 缺陷:
1.不可继承性
子线程不能继承主线程的私有变量
2.脏数据
在一个线程中读取到了不属于自己的信息
脏数据解决方法:
a> 避免使用静态变量
b>使用完之后,执行 remove 操作
3.容易造成内存溢出:
当一个线程使用完之后,没有释放资源,或者说释放资源不及时就是内存溢出
内存溢出的原因:(前置条件是使用线程池)
1> 线程池是长生命周期
2>Thread->ThreadLocalMap->Entry key,value(强引用) 垃圾回收器就不会回收value资源
解决内存溢出问题:使用完之后,执行 remove 操作