在java.lang.Thread类中有两个属性
ThreadLocal.ThreadLocalMap threadLocals
ThreadLocal.ThreadLocalMap inheritableThreadLocals
这里的ThreadLocalMap 类相当于一个Map,key 是 ThreadLocal 对象,value 就是存储的值。
threadLocals 里边的值是当前线程私有的,是线程安全的,threadLocals里可以存储一些对于线程安全有要求的对象,当下一次使用该线程时,threadLocals中的对象可以复用。当该线程消失之后,threadLocals 中的对象会被垃圾回收(如果对象被引用将不被回收)。
inheritableThreadLocals 中的值是可以被子线程继承的,inheritableThreadLocals 里可以存储一些允许被子线程使用的对象,下一次使用该线程并且创建子线程时,inheritableThreadLocals 中的对象可以复用。
举个栗子:
public static void main(String[] args) {
ThreadLocal<String> localString = new ThreadLocal<String>();
ThreadLocal<Long> localLong = new ThreadLocal<Long>();
ThreadLocal<String> inherLocalString = new InheritableThreadLocal <String>();
ThreadLocal<Long> inherLocalLong = new InheritableThreadLocal <Long>();
// 定义一个线程池
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(4, 10, 10L, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(512),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy());
// 线程的计数器
CountDownLatch main = new CountDownLatch(12);
// 定义多线程执行的任务
Runnable runnable = new Runnable() {
@Override
public void run() {
String name = Thread.currentThread().getName();
long id = Thread.currentThread().getId();
String myString = localString.get();
String myInherString = inherLocalString.get();
Long myLong = localLong.get();
Long myInherLong = inherLocalLong.get();
if (StringUtils.isBlank(myString)) {
myString = name;
localString.set(myString);
System.out.println(name+" 线程 localString 存储 myString:"+myString);
}
if (StringUtils.isBlank(myInherString)) {
myInherString = name;
inherLocalString.set(myInherString);
System.out.println(name+" 线程 inherLocalString 存储 myInherString:"+myInherString);
}
if (null == myLong) {
myLong = id;
localLong.set(myLong);
System.out.println(name+" 线程 localString 存储 myLong:"+myLong);
}
if (null == myInherLong) {
myInherLong = id;
inherLocalLong.set(myInherLong);
System.out.println(name+" 线程 inherLocalLong 存储 myInherLong:"+myInherLong);
}
System.out.println(name+" 线程的 myString:"+myString);
System.out.println(name+" 线程的 myLong:"+myLong);
System.out.println(name+" 线程的 myInherString:"+myInherString);
System.out.println(name+" 线程的 myInherLong:"+myInherLong);
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(name+" 线程的子线程获取 myString:"+localString.get());
System.out.println(name+" 线程的子线程获取 myLong:"+localLong.get());
System.out.println(name+" 线程的子线程获取 myInherString:"+inherLocalString.get());
System.out.println(name+" 线程的子线程获取 myInherLong:"+inherLocalLong.get());
// 线程执行完毕,主线程计数器减1;
main.countDown();
}
}).start();
}
};
// 开辟12条线程执行任务
for (int i = 0; i < 12; i++) {
threadPool.execute(runnable);
// 分隔符
if (i == 3 || i == 7) {
for (int j = 1; j <= 2100000000; j++) {
if (j == 2100000000) {
System.out.println("=================================");
}
}
}
}
try {
// 主线程阻塞,等待计数器计数归零后继续执行。
main.await();
System.out.println("所有线程任务执行完毕,回收所有的ThreadLocal。");
localString.remove();
localLong.remove();
inherLocalString.remove();
inherLocalLong.remove();
System.out.println("线程池不用了。关闭线程池。如果之前没有对ThreadLocal进行回收,线程池关闭后,线程里的ThreadLocal会被回收。");
threadPool.shutdown();
} catch (InterruptedException e) {
// shutdown()会在线程任务都执行完毕后将线程池关闭。
threadPool.shutdown();
}
}
运行结果:
pool-1-thread-2 线程 localString 存储 myString:pool-1-thread-2
pool-1-thread-2 线程 inherLocalString 存储 myInherString:pool-1-thread-2
pool-1-thread-1 线程 localString 存储 myString:pool-1-thread-1
pool-1-thread-3 线程 localString 存储 myString:pool-1-thread-3
pool-1-thread-4 线程 localString 存储 myString:pool-1-thread-4
pool-1-thread-3 线程 inherLocalString 存储 myInherString:pool-1-thread-3
pool-1-thread-1 线程 inherLocalString 存储 myInherString:pool-1-thread-1
pool-1-thread-4 线程 inherLocalString 存储 myInherString:pool-1-thread-4
pool-1-thread-2 线程 localString 存储 myLong:11
pool-1-thread-3 线程 localString 存储 myLong:12
pool-1-thread-1 线程 localString 存储 myLong:10
pool-1-thread-4 线程 localString 存储 myLong:13
pool-1-thread-1 线程 inherLocalLong 存储 myInherLong:10
pool-1-thread-3 线程 inherLocalLong 存储 myInherLong:12
pool-1-thread-3 线程的 myString:pool-1-thread-3
pool-1-thread-3 线程的 myLong:12
pool-1-thread-3 线程的 myInherString:pool-1-thread-3
pool-1-thread-2 线程 inherLocalLong 存储 myInherLong:11
pool-1-thread-3 线程的 myInherLong:12
pool-1-thread-1 线程的 myString:pool-1-thread-1
pool-1-thread-4 线程 inherLocalLong 存储 myInherLong:13
pool-1-thread-1 线程的 myLong:10
pool-1-thread-2 线程的 myString:pool-1-thread-2
pool-1-thread-1 线程的 myInherString:pool-1-thread-1
pool-1-thread-4 线程的 myString:pool-1-thread-4
pool-1-thread-1 线程的 myInherLong:10
pool-1-thread-2 线程的 myLong:11
pool-1-thread-2 线程的 myInherString:pool-1-thread-2
pool-1-thread-2 线程的 myInherLong:11
pool-1-thread-4 线程的 myLong:13
pool-1-thread-4 线程的 myInherString:pool-1-thread-4
pool-1-thread-4 线程的 myInherLong:13
pool-1-thread-4 线程的子线程获取 myString:null
pool-1-thread-4 线程的子线程获取 myLong:null
pool-1-thread-1 线程的子线程获取 myString:null
pool-1-thread-1 线程的子线程获取 myLong:null
pool-1-thread-1 线程的子线程获取 myInherString:pool-1-thread-1
pool-1-thread-1 线程的子线程获取 myInherLong:10
pool-1-thread-4 线程的子线程获取 myInherString:pool-1-thread-4
pool-1-thread-4 线程的子线程获取 myInherLong:13
pool-1-thread-3 线程的子线程获取 myString:null
pool-1-thread-2 线程的子线程获取 myString:null
pool-1-thread-2 线程的子线程获取 myLong:null
pool-1-thread-3 线程的子线程获取 myLong:null
pool-1-thread-3 线程的子线程获取 myInherString:pool-1-thread-3
pool-1-thread-2 线程的子线程获取 myInherString:pool-1-thread-2
pool-1-thread-2 线程的子线程获取 myInherLong:11
pool-1-thread-3 线程的子线程获取 myInherLong:12
=================================
pool-1-thread-2 线程的 myString:pool-1-thread-2
pool-1-thread-3 线程的 myString:pool-1-thread-3
pool-1-thread-1 线程的 myString:pool-1-thread-1
pool-1-thread-4 线程的 myString:pool-1-thread-4
pool-1-thread-1 线程的 myLong:10
pool-1-thread-3 线程的 myLong:12
pool-1-thread-2 线程的 myLong:11
pool-1-thread-2 线程的 myInherString:pool-1-thread-2
pool-1-thread-3 线程的 myInherString:pool-1-thread-3
pool-1-thread-1 线程的 myInherString:pool-1-thread-1
pool-1-thread-4 线程的 myLong:13
pool-1-thread-4 线程的 myInherString:pool-1-thread-4
pool-1-thread-1 线程的 myInherLong:10
pool-1-thread-3 线程的 myInherLong:12
pool-1-thread-2 线程的 myInherLong:11
pool-1-thread-4 线程的 myInherLong:13
pool-1-thread-1 线程的子线程获取 myString:null
pool-1-thread-1 线程的子线程获取 myLong:null
pool-1-thread-1 线程的子线程获取 myInherString:pool-1-thread-1
pool-1-thread-1 线程的子线程获取 myInherLong:10
pool-1-thread-2 线程的子线程获取 myString:null
pool-1-thread-2 线程的子线程获取 myLong:null
pool-1-thread-2 线程的子线程获取 myInherString:pool-1-thread-2
pool-1-thread-2 线程的子线程获取 myInherLong:11
pool-1-thread-3 线程的子线程获取 myString:null
pool-1-thread-3 线程的子线程获取 myLong:null
pool-1-thread-3 线程的子线程获取 myInherString:pool-1-thread-3
pool-1-thread-4 线程的子线程获取 myString:null
pool-1-thread-4 线程的子线程获取 myLong:null
pool-1-thread-4 线程的子线程获取 myInherString:pool-1-thread-4
pool-1-thread-4 线程的子线程获取 myInherLong:13
pool-1-thread-3 线程的子线程获取 myInherLong:12
=================================
pool-1-thread-1 线程的 myString:pool-1-thread-1
pool-1-thread-3 线程的 myString:pool-1-thread-3
pool-1-thread-3 线程的 myLong:12
pool-1-thread-3 线程的 myInherString:pool-1-thread-3
pool-1-thread-3 线程的 myInherLong:12
pool-1-thread-2 线程的 myString:pool-1-thread-2
pool-1-thread-2 线程的 myLong:11
pool-1-thread-2 线程的 myInherString:pool-1-thread-2
pool-1-thread-2 线程的 myInherLong:11
pool-1-thread-4 线程的 myString:pool-1-thread-4
pool-1-thread-1 线程的 myLong:10
pool-1-thread-3 线程的子线程获取 myString:null
pool-1-thread-3 线程的子线程获取 myLong:null
pool-1-thread-4 线程的 myLong:13
pool-1-thread-2 线程的子线程获取 myString:null
pool-1-thread-2 线程的子线程获取 myLong:null
pool-1-thread-2 线程的子线程获取 myInherString:pool-1-thread-2
pool-1-thread-2 线程的子线程获取 myInherLong:11
pool-1-thread-3 线程的子线程获取 myInherString:pool-1-thread-3
pool-1-thread-1 线程的 myInherString:pool-1-thread-1
pool-1-thread-1 线程的 myInherLong:10
pool-1-thread-3 线程的子线程获取 myInherLong:12
pool-1-thread-4 线程的 myInherString:pool-1-thread-4
pool-1-thread-4 线程的 myInherLong:13
pool-1-thread-1 线程的子线程获取 myString:null
pool-1-thread-1 线程的子线程获取 myLong:null
pool-1-thread-1 线程的子线程获取 myInherString:pool-1-thread-1
pool-1-thread-1 线程的子线程获取 myInherLong:10
pool-1-thread-4 线程的子线程获取 myString:null
pool-1-thread-4 线程的子线程获取 myLong:null
pool-1-thread-4 线程的子线程获取 myInherString:pool-1-thread-4
pool-1-thread-4 线程的子线程获取 myInherLong:13
所有线程任务执行完毕,回收所有的ThreadLocal。
线程池不用了。关闭线程池。如果之前没有对ThreadLocal进行回收,线程池关闭后,线程里的ThreadLocal会被回收。
可以看出线程1、2、3、4都存储了自己的myString、myLong、myInherString、myInherLong,其中myInherString、myInherLong可以被子线程使用,当再次连接线程1、2、3、4时,线程中存储的myString、myLong、myInherString、myInherLong可以被复用,myInherString、myInherLong依然可以被子线程使用。
对于一些我们希望可以被多线程复用,又担心这些对象线程不安全的情况下,可以使用ThreadLocal或InheritableThreadLocal来解决问题。例如SimpleDateFormat类的对象。
注意:自定义的ThreadLocal或InheritableThreadLocal在使用完毕后要回收。threadLocal.remove()。避免在线程池不关闭的情况下threadLocals中的对象无法回收导致内存溢出。参考博客:Java并发:ThreadLocal详解