不管用那种语言,在并发编程中遇见的问题都是类似的,只不每种语言提供的方法和工具不一样而已。
对于每个线程独享某个对象或者每个线程独立保存信息的场景,java提供的解决方法是ThreadLocal ,
对于线程独享某个对象的例子
public class ThreadLocalDemo {
public static ExecutorService threadPool = Executors.newFixedThreadPool(16);
SimpleDateFormat dateFormat = new SimpleDateFormat("mm:ss");
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 1000; i++) {
int finalI = i;
threadPool.submit(new Runnable() {
@Override
public void run() {
String date = new ThreadLocalDemo().date(finalI);
System.out.println(date);
}
});
}
threadPool.shutdown();
}
public String date(int seconds) {
Date date = new Date(1000 * seconds);
SimpleDateFormat simpleDateFormat = ThreadSafeFormatter.dateFormatThreadLocal.get();
return simpleDateFormat.format(date);
}
}
class ThreadSafeFormatter {
public static ThreadLocal<SimpleDateFormat> dateFormatThreadLocal = new ThreadLocal<SimpleDateFormat>() {
@Override
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat("mm:ss");
}
};
}
首先是用了带有16个线程的线程池,每个线程中threadlocal来保存各自的dateformate。避免每个线程新建一个dateformate 对象的开销,如果每个线程用同一个dateformate 又会造成线程不安全的问题。
对于每个线程中多个方法都需要使用的参数也可以放在threadlocal中,免去传参的麻烦。
和明显threadlocal和synchronized 思路相反。
有一种情况是某个thread需要多个threadlocal,这些threadlocals 被放在Thread类中了,被ThreadLocalMap 保存,key是某一个Tthreadlocal,值就是保管在threadlocal中的value了。上源码
public T get() {
//获取到当前线程
Thread t = Thread.currentThread();
//获取到当前线程内的 ThreadLocalMap 对象,每个线程内都有一个 ThreadLocalMap 对象
ThreadLocalMap map = getMap(t);
if (map != null) {
//获取 ThreadLocalMap 中的 Entry 对象并拿到 Value
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
//如果线程内之前没创建过 ThreadLocalMap,就创建
return setInitialValue();
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
可以看出每次get都会先拿到线程中保存的ThreadLocalMap,再用threadlcoal作为key取出该map中的value。
而threadLocalMpa 源码为
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
private Entry[] table;
//...
}