1、简介
ThreadLocal是解决线程安全问题一个很好的思路,它通过为每个线程提供一个独立的变量副本解决了变量并发访问的冲突问题。在很多情况下,ThreadLocal比直接使用synchronized同步机制解决线程安全问题更简单,更方便,且结果程序拥有更高的并发性。
ThreadLocal是线程Thread中属性threadLocals的管理者。
2、ThreadLocal类中提供了几个方法:
-
public T get() { }
-
public void set(T value) { }
-
public void remove() { }
-
protected T initialValue(){ }
3、使用场景
-
每个线程需要有自己单独的实例
-
实例需要在多个方法中共享,但不希望被多线程共享
对于第一点,每个线程拥有自己实例,实现它的方式很多。例如可以在线程内部构建一个单独的实例。ThreadLoca 可以以非常方便的形式满足该需求。
对于第二点,可以在满足第一点(每个线程有自己的实例)的条件下,通过方法间引用传递的形式实现。ThreadLocal 使得代码耦合度更低,且实现更优雅。扩展:来探讨一下最近面试问的ThreadLocal问题
1)存储用户Session
一个简单的用ThreadLocal来存储Session的例子:
private static final ThreadLocal threadSession = new ThreadLocal();
public static Session getSession() throws InfrastructureException {
Session s = (Session) threadSession.get();
try {
if (s == null) {
s = getSessionFactory().openSession();
threadSession.set(s);
}
} catch (HibernateException ex) {
throw new InfrastructureException(ex);
}
return s;
}
2)解决线程安全的问题
比如Java7中的SimpleDateFormat不是线程安全的,可以用ThreadLocal来解决这个问题:
public class DateUtil {
private static ThreadLocal<SimpleDateFormat> format1 = new ThreadLocal<SimpleDateFormat>() {
@Override
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
};
public static String formatDate(Date date) {
return format1.get().format(date);
}
}
这里的DateUtil.formatDate()就是线程安全的了。(Java8里的 java.time.format.DateTimeFormatter是线程安全的,Joda time里的DateTimeFormat也是线程安全的)。
4、总结
ThreadLocal 适用于每个线程需要自己独立的实例且该实例需要在多个方法中被使用,也即变量在线程间隔离而在方法或类间共享的场景。
评论区