标签:种类 app 十分 als 散列表 一个 解耦 赋值 string
ThreadLocal是线程内部的数据存储类,通过它可以指定的线程中存储数据,数据存储以后,只有在指定线程中可以获取到存储的数据,对于其他线程来说则无法获取数据。
它能够满足以下需求:
时间解析类SimpleDateFormat是线程不安全的典型例子,因为同一时刻下只能支持一个解析表达式,多线程环境下使用只有两种选择:
private static final ThreadLocal<SimpleDateFormat> threadLocal = new ThreadLocal<>();
static String format(Date date, String pattern) {
SimpleDateFormat simpleDateFormat = threadLocal.get();
if (simpleDateFormat == null) {
simpleDateFormat = new SimpleDateFormat();
threadLocal.set(simpleDateFormat);
}
simpleDateFormat.applyPattern(pattern);
return simpleDateFormat.format(date);
}
接下来我们尝试着自己设计一个方案,让线程随时随地可以拥有自己的线程私有变量。通过设计方案的演变来帮助理解JDK的方案。
线程私有变量有两个保存地方可以选择:
最先想到的办法,也是最直白的,是通过Map来持有多个线程私有变量。
public class ThreadLocalInside extends Thread {
WeakHashMap<Object, Object> threadLocals = new WeakHashMap<>();
}
自己灵活的设置key来区分不同的线程私有变量。
static String format(Date date, String pattern) {
ThreadLocalInside thread = (ThreadLocalInside) Thread.currentThread();
Class clazz = SimpleDateFormat.class;
SimpleDateFormat simpleDateFormat = (SimpleDateFormat) thread.threadLocals.get(clazz);
if (simpleDateFormat == null) {
simpleDateFormat = new SimpleDateFormat();
thread.threadLocals.put(clazz, simpleDateFormat);
}
simpleDateFormat.applyPattern(pattern);
return simpleDateFormat.format(date);
}
public class ThreadLocalOutside extends WeakHashMap<Thread, HashMap<Object, Object>> {
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
@Override
public HashMap<Object, Object> put(Thread key, HashMap<Object, Object> value) {
lock.writeLock().lock();
try {
return super.put(key, value);
} finally {
lock.writeLock().unlock();
}
}
public HashMap<Object, Object> get(Thread key) {
lock.readLock().lock();
try {
return super.get(key);
} finally {
lock.readLock().unlock();
}
}
}
private static final ThreadLocalOutside THREAD_LOCAL_MANAGER = new ThreadLocalOutside();
static String format(Date date, String pattern) {
Thread thread = Thread.currentThread();
HashMap<Object, Object> threadLocalVariable = THREAD_LOCAL_MANAGER.get(thread);
Class clazz = SimpleDateFormat.class;
SimpleDateFormat simpleDateFormat = (SimpleDateFormat) threadLocalVariable.get(clazz);
if (simpleDateFormat == null) {
simpleDateFormat = new SimpleDateFormat();
threadLocalVariable.put(clazz, simpleDateFormat);
}
simpleDateFormat.applyPattern(pattern);
return simpleDateFormat.format(date);
}
JDK的ThreadLocal包含了上面两种设计思想,即保存在线程内,却通过外部类提供API来操作。
新引入了一个设计:使用ThreadLocal对象作为私有变量集合的Key,每一个ThreadLocal对象代表一个种类的线程私有变量。这个设计解决了线程私有变量管理的痛点:
为了不让读者的注意力被弱引用散列表的实现细节分散,这里使用WeakHashMap代替ThreadLocal内部的ThreadLocalMap。
简单介绍以下这两个集合功能:
public class Thread2 extends Thread {
//ThreadLocal作为key,一个ThreadLocal代表一种线程私有变量
WeakHashMap<ThreadLocal2, Object> threadLocals;
}
class ThreadLocal2<T> {
//模板方法
protected T initialValue() {
return null;
}
public T get() {
Thread2 thread = (Thread2) Thread.currentThread();
WeakHashMap<ThreadLocal2, Object> threadLocalMap = thread.threadLocals;
if (threadLocalMap != null) {
Object value = threadLocalMap.get(this);
if (value != null) {
return (T) value;
}
}
T value = initialValue();
if (threadLocalMap != null) {
threadLocalMap.put(this, value);
} else {
//懒加载,大部分线程不使用threadLocal,因此能节约不少内存
thread.threadLocals = new WeakHashMap<>();
thread.threadLocals.put(this, value);
}
return value;
}
public void set(T object) {
Thread2 thread = (Thread2) Thread.currentThread();
WeakHashMap<ThreadLocal2, Object> threadLocalMap = thread.threadLocals;
if (threadLocalMap != null) {
threadLocalMap.put(this, object);
} else {
//懒加载,大部分线程不使用threadLocal,因此能节约不少内存
thread.threadLocals = new WeakHashMap<>();
thread.threadLocals.put(this, initialValue());
}
}
}
使用起来几乎和JDK实现的ThreadLocal一模一样呢
private static final ThreadLocal2<SimpleDateFormat> threadLocal = new ThreadLocal2<>() ;
static String format(Date date, String pattern) {
SimpleDateFormat simpleDateFormat = threadLocal.get();
if (simpleDateFormat == null) {
simpleDateFormat = new SimpleDateFormat();
threadLocal.set(simpleDateFormat);
}
simpleDateFormat.applyPattern(pattern);
return simpleDateFormat.format(date);
}
简直是去其糟粕取其精华。
标签:种类 app 十分 als 散列表 一个 解耦 赋值 string
原文地址:https://www.cnblogs.com/datartvinci/p/11069913.html