注:本文参考诸葛老师的视频所记录
- ThreadLocal 是 Java中所提供的线程本地存储机制,可以利用该机制将数据缓存在某个线程内部,该线程可以在任意时刻,任意方法中获取缓存的数据
- ThreadLocal 底层是通过ThreadLocalMap 来实现的,每个Thread对象(注意不是Thread对象)中都存在一个ThreadLocalMap,Map的key为ThreadLocal对象,Map的value为需要存储的值;
- 如果在线程池中使用ThreadLocal 会造成内存泄漏,因为当ThreadLocal对象使用完之后,应该要把设置的Key,Value ,也就是Entry对象进行回收,但线程池中的线程不会回收,而线程对象是通过强引用只想ThreadLocalMap,ThreadLocalMap也是通过强引用指向Entry对象,线程不被回收,Entry对象也不被回收,从而出现内存泄漏,解决办法:在使用ThreadLocal对象之后,手动调用ThreadLocal的remove方法,手动清除Entry对象
- ThreadLocal 经典的应用场景就是连接管理(一个线程持有一个连接,该连接对象可以在不同的方法之间传递,线程之间不共享一个连接)
public class ThreadLocalStudy {
public static void main(String[] args) {
Person person = new Person();
new Thread(new Runnable() {
@Override
public void run() {
person.setName("法外狂徒张三");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程:"+Thread.currentThread() + "=========" + person.getName());
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
person.setName("法内狂徒罗翔");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程:"+Thread.currentThread() + "=========" + person.getName());
}
}).start();
Stu stu = new Stu();
new Thread(new Runnable() {
@Override
public void run() {
stu.setName("法外狂徒张三");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程:"+Thread.currentThread() + "=========" + stu.getName());
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
stu.setName("法内狂徒罗翔");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程:"+Thread.currentThread() + "=========" + stu.getName());
}
}).start();
}
}
class Person{
/**
* 多个线程共用这个对象
*/
private ThreadLocal<String> name = new ThreadLocal<>();
public void setName(String name) {
this.name.set(name);
}
public String getName() {
return name.get();
}
}
class Stu{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
使用ThreadLocal可以达到线程隔离的效果
结果对比
线程:Thread[Thread-0,5,main]=========法外狂徒张三
线程:Thread[Thread-1,5,main]=========法内狂徒罗翔
线程:Thread[Thread-2,5,main]=========法内狂徒罗翔
线程:Thread[Thread-3,5,main]=========法内狂徒罗翔